OCP Java SE 7 Programmer II Certification Guide Prepare For The 1ZO 804 Exam
User Manual: Pdf
Open the PDF directly: View PDF .
Page Count: 834
Download | |
Open PDF In Browser | View PDF |
Prepare for the 1ZO-804 exam Mala Gupta MANNING www.allitebooks.com OCP Java SE 7 Programmer II Certification Guide Licensed to Mark Watsonwww.allitebooks.com Licensed to Mark Watson www.allitebooks.com OCP Java SE 7 Programmer II Certification Guide PREPARE FOR THE 1ZO-804 EXAM MALA GUPTA MANNING SHELTER ISLAND Licensed to Mark Watson www.allitebooks.com For online information and ordering of this and other Manning books, please visit www.manning.com. The publisher offers discounts on this book when ordered in quantity. For more information, please contact Special Sales Department Manning Publications Co. 20 Baldwin Road PO Box 761 Shelter Island, NY 11964 Email: orders@manning.com ©2015 by Manning Publications Co. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by means electronic, mechanical, photocopying, or otherwise, without prior written permission of the publisher. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in the book, and Manning Publications was aware of a trademark claim, the designations have been printed in initial caps or all caps. Recognizing the importance of preserving what has been written, it is Manning’s policy to have the books we publish printed on acid-free paper, and we exert our best efforts to that end. Recognizing also our responsibility to conserve the resources of our planet, Manning books are printed on paper that is at least 15 percent recycled and processed without the use of elemental chlorine. Manning Publications Co. 20 Baldwin Road PO Box 761 Shelter Island, NY 11964 Development editor: Technical editor: Copyeditor: Proofreader: Technical proofreaders: Typesetter: Cover designer: Cynthia Kane George Zurowski Jodie Allen Alyson Brener Roel De Nijs, Jean-François Morin Dennis Dalinnik Marija Tudor ISBN: 9781617291487 Printed in the United States of America 1 2 3 4 5 6 7 8 9 10 – MAL – 20 19 18 17 16 15 Licensed to Mark Watson www.allitebooks.com To Dheeraj, my pillar of strength Licensed to Mark Watson www.allitebooks.com Licensed to Mark Watson www.allitebooks.com brief contents Introduction 1 1 ■ Java class design 13 2 ■ Advanced class design 95 3 ■ Object-oriented design principles 172 4 ■ Generics and collections 242 5 ■ String processing 348 6 ■ Exceptions and assertions 396 7 ■ Java I/O fundamentals 463 8 ■ Java file I/O (NIO.2) 512 9 ■ Building database applications with JDBC 577 10 ■ Threads 627 11 ■ Concurrency 679 12 ■ Localization 719 vii Licensed to Mark Watson www.allitebooks.com Licensed to Mark Watson www.allitebooks.com contents preface xxi acknowledgments xxiii about this book xxv Introduction 1 Disclaimer 2 Introduction to OCP Java SE 7 Programmer II certification (1Z0-804) 2 The importance of the OCP Java SE 7 Programmer II certification 2 Comparing the OCA Java SE 7 Programmer I (1Z0-803) and OCP Java SE 7 Programmer II (1Z0-804) exams 4 Complete exam objectives, mapped to book chapters, and readiness checklist 4 ■ FAQ 7 FAQ on exam preparation 8 ■ FAQ on taking the exam 9 The testing engine used in the exam 11 ix Licensed to Mark Watson www.allitebooks.com CONTENTS x 1 Java class design 13 1.1 Java access modifiers 15 Public access modifier 16 Protected access modifier 17 Default access (package access) 19 The private access modifier 23 Access modifiers and Java entities 25 Effects of changing access modifiers for existing entities 26 ■ ■ ■ 1.2 Overloaded methods and constructors 28 Argument list 30 overloaded methods 1.3 ■ When methods can’t be defined as 34 Overloaded constructors 35 ■ Method overriding and virtual method invocation 40 Need of overridden methods 41 Correct syntax of overriding methods 44 Can you override all methods from the base class or invoke them virtually? 48 Identifying method overriding, overloading, and hiding 49 Can you override base class constructors or invoke them virtually? 50 ■ ■ ■ ■ 1.4 Overriding methods of class Object 51 Overriding method toString() 51 Overriding method equals() 54 Overriding method hashCode() 60 ■ ■ 1.5 Casting and the instanceof operator 66 Implicit and explicit casting 67 Combinations of casting Using the instanceof operator 73 ■ 1.6 70 Packages 75 The need for packages 75 Defining classes in a package using the package statement 76 Using simple names with import statements 78 Using packages without using the import statement 79 Importing a single member versus all members of a package 80 The import statement doesn’t import the whole package tree 80 Importing classes from the default package 81 Static imports 81 ■ ■ ■ ■ ■ ■ ■ 1.7 1.8 Summary 82 Review notes 83 Java access modifiers 83 Overloaded methods and constructors 84 Method overriding and virtual method invocation 84 Java packages 85 ■ ■ ■ 1.9 1.10 Sample exam questions 85 Answers to sample exam questions 90 Licensed to Mark Watson CONTENTS 2 xi Advanced class design 95 2.1 Abstract classes and their application 97 Identify abstract classes 97 Construct abstract classes and subclasses 100 Understand the need for abstract classes 103 Follow the do’s and don’t’s of creating and using abstract classes 103 Compare abstract classes and concrete classes 105 ■ ■ ■ 2.2 Static and final keywords 106 Static modifier 2.3 107 ■ Nonaccess modifier—final 115 Enumerated types 122 Understanding the need for and creating an enum 123 Adding implicit code to an enum 124 Extending java.lang.Enum 125 Adding variables, constructors, and methods to your enum 127 Where can you define an enum? 130 ■ ■ ■ 2.4 Static nested and inner classes 132 Advantages of inner classes 133 Static nested class (also called static inner class) 134 Inner class (also called member class) 139 Anonymous inner classes 147 Method local inner classes 152 Disadvantages of inner classes 153 ■ ■ ■ ■ 2.5 2.6 Summary 154 Review notes 154 Abstract classes 154 Nonaccess modifier—static 155 Nonaccess modifier—final 155 Enumerated types 156 Static nested classes 157 Inner classes 158 Anonymous inner classes 158 Method local inner classes 159 ■ ■ ■ ■ ■ 2.7 2.8 3 Sample exam questions 159 Answers to sample exam questions 166 Object-oriented design principles 172 3.1 Interfaces 174 Understanding interfaces 175 Declaring interfaces 176 Implementing interfaces 179 Extending interfaces 183 ■ ■ 3.2 Class inheritance versus interface inheritance 184 Comparing class inheritance and interface inheritance 184 Preferring class inheritance over interface inheritance 185 Preferring interface inheritance over class inheritance 186 Licensed to Mark Watson CONTENTS xii 3.3 IS-A and HAS-A relationships in code 190 Identifying and implementing an IS-A relationship 191 Identifying and implementing a HAS-A relationship 196 3.4 Cohesion and low coupling Cohesion 3.5 3.6 197 ■ Coupling 197 198 Object composition principles 200 Introduction to design patterns 201 What is a design pattern? 201 design pattern? 201 3.7 ■ Why do you need a Singleton pattern 202 Why do you need this pattern? 202 Implementing the Singleton pattern 202 Ensuring creation of only one object in the Singleton pattern 203 Comparing Singleton with global data 207 ■ ■ ■ 3.8 Factory pattern 208 Simple Factory pattern (or Static Factory pattern) 208 Factory Method pattern 210 Abstract Factory pattern 211 Benefits of the Factory pattern 213 Using the Factory pattern from the Java API 214 ■ ■ 3.9 DAO pattern 215 What is the DAO pattern? 215 Implementing the DAO pattern 215 Using the Simple Factory pattern with the DAO pattern 217 Using the Factory Method or Abstract Factory pattern with the DAO pattern 218 Benefits of the DAO pattern 220 ■ ■ ■ 3.10 3.11 Summary 220 Review notes 222 Interfaces 222 Class inheritance versus interface inheritance 223 IS-A and HAS-A relationships in code 223 Cohesion and low coupling 223 Object composition principles 224 Singleton pattern Factory pattern 225 DAO pattern 226 ■ ■ ■ ■ 224 ■ 3.12 3.13 4 Sample exam questions 226 Answers to sample exam questions 234 Generics and collections 242 4.1 Introducing generics: WARM-UP 244 Need for introducing generics 244 of using generics 245 ■ Benefits and complexities Licensed to Mark Watson CONTENTS 4.2 xiii Creating generic entities 246 Creating a generic class 246 Working with generic interfaces 250 Using generic methods 252 Bounded type parameters 253 Using wildcards 255 Using bounded wildcards 257 Type erasure 260 Refreshing the commonly used terms 262 ■ ■ ■ ■ 4.3 Using type inference 263 Using type inference to instantiate a generic class 264 Using type inference to invoke generic methods 265 4.4 Understanding interoperability of collections using raw types and generic types 265 Mixing reference variables and objects of raw and generic types Subtyping with generics 270 4.5 4.6 Introducing the collections framework: WARM-UP Working with the Collection interface 273 The core Collection interface 274 Collection interface 275 4.7 ■ 266 271 Methods of the Creating and using List, Set, and Deque implementations 276 List interface and its implementations 276 Deque interface and its implementations 282 Set interface and its implementations 290 Set implementation classes 291 ■ ■ ■ 4.8 Map and its implementations 296 Map interface 296 TreeMap 305 4.9 ■ HashMap 297 LinkedHashMap 304 Using java.util.Comparator and java.lang.Comparable 308 Comparable interface 308 4.10 ■ ■ Comparator interface 310 Sorting and searching arrays and lists 313 Sorting arrays 313 Sorting List using Collections Searching arrays and List using collections 318 ■ 4.11 317 Using wrapper classes 320 Class hierarchy of wrapper classes 320 Creating objects of the wrapper classes 321 Retrieving primitive values from the wrapper classes 322 Parsing a string value to a primitive type 322 Difference between using method valueOf() and constructors of wrapper classes 323 Comparing objects of wrapper classes 323 ■ ■ ■ ■ Licensed to Mark Watson CONTENTS xiv 4.12 4.13 4.14 Autoboxing and unboxing Summary 327 Review notes 328 325 Creating generic entities 328 Using type inference 330 Understanding interoperability of collections using raw types and generic types 330 Working with the Collection interface 330 Creating and using List, Set, and Deque implementations 331 Map and its implementations 334 Using java.util.Comparator and java.lang.Comparable 336 Sorting and searching arrays and lists 336 Using wrapper classes 337 Autoboxing and Unboxing 337 ■ ■ ■ ■ ■ 4.15 4.16 5 Sample exam questions 338 Answers to sample exam questions 343 String processing 348 5.1 Regular expressions 349 What is a regular expression? 351 Character classes 351 Predefined character classes 354 Matching boundaries 356 Quantifiers 358 Java’s regex support 362 ■ ■ ■ 5.2 Searching, parsing, and building strings 364 Searching strings 364 Replacing strings 368 Parsing and tokenizing strings with Scanner and StringTokenizer 372 ■ 5.3 Formatting strings 376 Formatting classes 376 Formatting methods 376 Defining format strings 377 Formatting parameter %b 379 Formatting parameter %c 380 Formatting parameters %d and %f 380 Formatting parameter %s 381 ■ ■ ■ ■ 5.4 5.5 Summary 382 Review notes 382 Regular expressions 382 Formatting strings 385 5.6 5.7 6 ■ Search, parse, and build strings 384 Sample exam questions 387 Answers to sample exam questions 391 Exceptions and assertions 396 6.1 Using the throw statement and the throws clause 398 Creating a method that throws a checked exception 400 Using a method that throws a checked exception 400 Licensed to Mark Watson CONTENTS xv Creating and using a method that throws runtime exceptions or errors 403 Points to note while using the throw statement and the throws clause 404 ■ 6.2 Creating custom exceptions 409 Creating a custom checked exception 410 unchecked exception 412 6.3 6.4 ■ Creating a custom Overriding methods that throw exceptions 413 Using the try statement with multi-catch and finally clauses 415 Comparing single-catch handlers and multi-catch handlers 415 Handling multiple exceptions in the same exception handler 416 6.5 Auto-closing resources with a try-with-resources statement 422 How to use a try-with-resources statement 422 Suppressed exceptions 424 The right ingredients 426 ■ 6.6 Using assertions 431 Exploring the forms of assertions 432 Testing invariants in your code 435 Understanding appropriate and inappropriate uses of assertions 439 ■ ■ 6.7 6.8 Summary 442 Review notes 443 Using the throw statement and the throws clause 443 Custom exceptions 444 Overriding methods that throw exceptions 444 try statement with multi-catch and finally clauses 445 Auto-close resources with try-with-resources statement 445 Assertions 446 ■ ■ ■ ■ 6.9 6.10 7 Sample exam questions 447 Answers to sample exam questions 456 Java I/O fundamentals 463 7.1 Introducing Java I/O: WARM-UP 464 Understanding streams flavors of data 465 7.2 464 ■ Understanding multiple Working with class java.io.File 469 Instantiating and querying File instances 470 Creating new files and directories on your physical device Licensed to Mark Watson 472 CONTENTS xvi 7.3 Using byte stream I/O 473 Input streams 473 Output streams 475 File I/O with byte streams 477 Buffered I/O with byte streams 481 Primitive values and strings I/O with byte streams 482 Object I/O with byte streams: reading and writing objects 484 ■ ■ ■ 7.4 Using character I/O with readers and writers 489 Abstract class java.io.Reader 491 Abstract class java.io.Writer 491 File I/O with character streams 492 Buffered I/O with character streams 493 Data streams with character streams: using PrintWriter to write to a file 494 Constructor chaining with I/O classes 496 ■ ■ ■ 7.5 7.6 7.7 Working with the console 497 Summary 499 Review notes 500 Working with class java.io.File 500 Using byte stream I/O 500 Using character I/O with readers and writers 502 Working with the console 503 ■ ■ ■ 7.8 7.9 8 Sample exam questions 504 Answers to sample exam questions 509 Java file I/O (NIO.2) 512 8.1 Path objects 516 Multiple ways to create Path objects 518 Methods to access Path components 521 Comparing paths 522 Converting relative paths to absolute paths 523 Resolving paths using methods resolve and resolveSibling 525 Method relativize() 526 ■ ■ 8.2 Class Files 527 Create files and directories 527 Check for the existence of files and directories 529 Copy files 530 Move files and directories 534 Delete files and directories 534 Commonly thrown exceptions 535 ■ ■ ■ ■ 8.3 Files and directory attributes 535 Individual attributes 535 Group of attributes 537 Basic attributes 540 DOS attributes 541 POSIX attributes 542 AclFileAttributeView interface 543 FileOwnerAttributeView interface 543 UserDefinedAttributeView interface 543 ■ ■ ■ ■ Licensed to Mark Watson CONTENTS 8.4 xvii Recursively access a directory tree 545 FileVisitor interface 546 Class SimpleFileVisitor 549 Initiate traversal for FileVisitor and SimpleFileVisitor 550 DirectoryStream interface 553 ■ 8.5 8.6 Using PathMatcher 555 Watch a directory for changes 557 Create WatchService object WatchService object 557 WatchKey interface 558 8.7 8.8 557 Register with Access watched events using Processing events 558 ■ ■ ■ Summary 561 Review notes 561 Path objects 561 Class Files 563 Files and directory attributes 564 Recursively access a directory tree 566 Using PathMatcher 566 Watch a directory for changes 567 ■ ■ ■ ■ 8.9 8.10 9 Sample exam questions 568 Answers to sample exam questions 573 Building database applications with JDBC 577 9.1 Introduction 578 JDBC API overview 579 JDBC drivers 580 9.2 ■ JDBC architecture 580 Interfaces that make up the JDBC API core 581 Interface java.sql.Driver 582 Interface java.sql.Connection 583 Interface java.sql.Statement 583 Interface java.sql.ResultSet 583 9.3 Connecting to a database 584 Loading JDBC drivers 585 Use DriverManager to connect to a database 586 Exceptions thrown by database connections 588 ■ ■ 9.4 CRUD (create, retrieve, update, and delete) operations 589 Read table definition and create table 590 Mapping SQL data types to Java data types 591 Insert rows in a table 592 Update data in a table 594 Delete data in a table 595 Querying database 595 ■ ■ ■ Licensed to Mark Watson CONTENTS xviii 9.5 JDBC transactions 599 A transaction example 599 Create savepoints and roll back partial transactions 601 Commit modes and JDBC transactions 603 ■ ■ 9.6 RowSet objects 603 Interface RowSetFactory 605 Class RowSetProvider 605 An example of working with JdbcRowSet 605 ■ 9.7 Precompiled statements 607 Prepared statements 607 Interface CallableStatement Database-stored procedures with parameters 612 ■ 9.8 9.9 610 Summary 613 Review notes 614 Introduction 614 Interfaces that make up the JDBC API core 615 Connecting to a database 615 CRUD (create, retrieve, update, and delete) operations 616 JDBC transactions 617 RowSet objects 617 Precompiled statements 618 ■ ■ ■ 9.10 9.11 10 Sample exam questions 619 Answers to sample exam questions 624 Threads 627 10.1 Create and use threads 629 Extending class Thread Runnable 632 10.2 630 ■ Implement interface Thread lifecycle 634 Lifecycle of a thread 634 Methods of class Thread 637 Start thread execution 637 Pause thread execution 639 End thread execution 645 ■ ■ 10.3 Protect shared data 645 Identifying shared data: WARM-UP 645 Thread interference 646 Thread-safe access to shared data 649 Immutable objects are thread safe 654 Volatile variables 655 ■ ■ ■ 10.4 Identify and fix code in a multithreaded environment 657 Variables you should care about 657 Operations you should care about 658 Waiting for notification of events: using wait, notify, and notifyAll 659 Deadlock 662 Starvation 663 Livelock 664 Happens-before relationship 664 ■ ■ ■ ■ ■ Licensed to Mark Watson CONTENTS 10.5 10.6 xix Summary 665 Review notes 665 Create and use threads 665 Thread lifecycle 666 Methods of class Thread 667 Protect shared data 668 Identify and fix code in a multithreaded environment 669 ■ ■ 10.7 10.8 11 Sample exam questions 670 Answers to sample exam questions 675 Concurrency 679 11.1 Concurrent collection classes 680 Interface BlockingQueue 681 Interface ConcurrentMap 682 Class ConcurrentHashMap 682 ■ 11.2 Locks 684 Acquire lock 685 Acquire lock and return immediately 686 Interruptible locks 688 Nonblock-structured locking 690 Interface ReadWriteLock 692 Class ReentrantReadWriteLock 692 Atomic variables 693 ■ ■ ■ 11.3 Executors 695 Interface Executor 696 Interface Callable 698 Interface ExecutorService 699 Thread pools 700 Interface ScheduledExecutorService 701 ■ ■ 11.4 11.5 11.6 Parallel fork/join framework Summary 708 Review notes 709 703 Concurrent collection classes 709 Locks 709 Executors 710 Parallel fork/join framework 711 ■ ■ 11.7 11.8 12 Sample exam questions 712 Answers to sample exam questions 716 Localization 719 12.1 Internationalization and localization 720 Advantages of localization 722 Class java.util.Locale 722 Creating and accessing Locale objects 723 Building locale-aware applications 727 ■ ■ 12.2 Resource bundles 728 Implementing resource bundles using .properties files 728 Implementing resource bundles using ListResourceBundle 733 Loading resource bundles for invalid values 735 Licensed to Mark Watson www.allitebooks.com CONTENTS xx 12.3 Formatting dates, numbers, and currencies for locales 737 Format numbers 738 Format currencies 740 Format dates 743 Formatting and parsing time for a specific locale 745 Formatting and parsing date and time together for a specific locale 746 Using custom date and time patterns with SimpleDateFormat 747 Creating class Date object using class Calendar 749 ■ ■ ■ ■ ■ 12.4 12.5 Summary 749 Review Notes 750 Internationalization and localization 750 Resource bundles 752 Formatting dates, numbers, and currencies for locales 753 ■ 12.6 12.7 appendix Sample exam questions 754 Answers to sample exam questions 758 Answers to “Twist in the Tale” exercises index 13 761 781 Full mock exam Available online only at www.manning.com/gupta2 Licensed to Mark Watson preface The OCP Java SE Programmer II certification is designed to tell would-be employers that you really know your basic and advanced Java stuff. It certifies that you understand and can work with design patterns and advanced Java concepts like concurrency, multithreading, localization, string processing, and JDBC. The exam preparation helps you to understand the finer details of the Java language and its implementation and usage, which is crucial to writing quality code. Cracking this exam is not an easy task. Thorough preparation is crucial if you want to pass the exam the first time with a score that you can be proud of. You need to know Java inside and out, and you need to understand the certification process so that you’re ready for the challenging questions you’ll face on the exam. This book is a comprehensive guide to the 1Z0-804 exam. You’ll explore a wide range of important Java topics as you systematically learn how to pass the certification exam. Each chapter starts with a list of the exam objectives covered in that chapter. Throughout the book you’ll find sample questions and exercises designed to reinforce key concepts and prepare you for what you’ll see on the real exam, along with numerous tips, notes, and visual aids. Unlike many other exam guides, this book provides multiple ways to digest important techniques and concepts, including comic conversations, analogies, pictorial representations, flowcharts, UML diagrams, and, naturally, lots of well-commented code. xxi Licensed to Mark Watson PREFACE xxii The book also gives insight into typical exam question mistakes and guides you in avoiding traps and pitfalls. It provides ■ ■ ■ ■ Complete coverage of exam topics, all mapped to chapter and section numbers Hands-on coding exercises, including particularly challenging ones that throw in a twist Instruction on what’s happening behind the scenes using the actual code from the Java API source Everything you need to master both the concepts and the exam This book is written for developers with a working knowledge of Java. My hope is that the book will deepen your knowledge, prepare you well for the exam, and that you will pass it with flying colors! Licensed to Mark Watson acknowledgments First and foremost, I thank Dheeraj. He helped me to get started with this book, and his guidance, encouragement, and love enabled me to get over the goal line. My sincere gratitude to Marjan Bace, publisher at Manning, for giving me the opportunity to author this book. An extremely talented individual, Cynthia Kane, my development editor at Manning, was a pleasure to work with. She not only helped me improve the organization of the chapters, she also pulled me up whenever the task of completing the book became overwhelming for me. The contributions of Roel De Nijs, technical proofreader on this book, are unparalleled. His feedback helped me to improve all sections and chapters. Jean-François Morin, technical proofreader for a few chapters, also helped me to improve the book just before it went into production. Gregor Zurowski, my technical editor, provided great insight and helped iron out technical glitches as the book was being written. Apart from applying her magic to sentence and language constructions, Jodie Allen, my copyeditor, was very supportive and patient in applying changes across all chapters. I’d also like to thank Ozren Harlovic, review editor, for managing the review process and meticulously funneling the feedback to me to make this book better. Mary Piergies, Alyson Brener, and Kevin Sullivan were awesome in their expertise at turning all text, code, and images into publishable form. I am also grateful to Candace Gillhoolley and Ana Radic for managing the promotion of this book. xxiii Licensed to Mark Watson xxiv ACKNOWLEDGMENTS Next, I’d like to thank all the MEAP readers for trusting me by buying the book while it was being written. I thank them for their patience, suggestions, corrections, and encouragement. Technical reviewers helped in validating the chapters’ contents at various stages of their development. The reviewers’ detailed and helpful feedback helped me to improve the book throughout the writing process: Alexander Schwartz, Ashutosh Sharma, Bill Weiland, Colin Hastie, Dylan Scott, Jamie Atkinson, Kevin Vig, Kyle Smith, Manish Verma, Mikael Strand, Mikalai Zaikin, Robin Coe, Simon Joseph Aquilina, Steve Etherington, and Witold Bolt. Special shout-out to Mikalai for his detailed feedback— it helped me to improve the contents enormously. I thank my former colleagues Harry Mantheakis, Paul Rosenthal, and Selvan Rajan, whose names I have used in coding examples throughout the book. I have always looked up to them. Finally, I thank my parents and my daughters, Shreya and Pavni. This book would have been not been possible without their unconditional support, love, and encouragement. Licensed to Mark Watson about this book This book is written for developers with a working knowledge of Java who want to earn the OCP Java SE 7 Programmer II certification (exam 1Z0-804). It uses powerful tools and features to make reaching your goal of certification a quick, smooth, and enjoyable experience. This section will explain the features used in the book and tell you how to use the book to get the most out of it as you prepare for the certification exam. More information on the exam and on how the book is organized is available in the Introduction. Start your preparation with the chapter-based exam objective map I strongly recommend a structured approach to preparing for this exam. To help you with this task, I’ve developed a chapter-based exam objective map, as shown in figure 1. The full version is in the Introduction (table 2). Exam objective as per Oracle’s website Covered in chapter/ section 1 Java Class Design Chapter 1 1.1 Use access modifiers: private, protected, and public Section 1.1 1.2 Override methods Section 1.3 1.3 Overload constructors and methods Section 1.2 Figure 1 The Introduction to this book provides a list of all exam objectives and the corresponding chapter and section numbers where they are covered. xxv Licensed to Mark Watson ABOUT THIS BOOK xxvi The map in the Introduction shows the complete exam objective list mapped to the relevant chapter and section numbers. You can jump to the relevant section number to work on a particular exam topic. Chapter-based objectives Each chapter starts with a list of the exam objectives covered in that chapter, as shown in figure 2. This list is followed by a quick comparison of the major concepts and topics covered in the chapter with real-world objects and scenarios. Exam objectives covered in this chapter What you need to know [3.1] Write code that declares, implements, and/or extends interfaces The need for interfaces. How to declare, implement, and extend interfaces. Implications of implicit modifiers that are added to an interface and its members. [3.2] Choose between interface inheritance and class inheritance The differences and similarities between implementing inheritance by using interfaces and by using abstract or concrete classes. Factors that favor using interface inheritance over class inheritance, and vice versa. Figure 2 An example of the list of exam objectives and brief explanations at the beginning of each chapter Section-based objectives Each main section in a chapter starts by identifying the exam objective(s) that it covers. Each listed exam topic starts with the exam objective and its subobjective number. In figure 3, the number 4.2 refers to section 4.2 in chapter 4 (the complete list of chapters and sections can be found in the contents). The 4.1 preceding the exam objective refers to the objective’s numbering in the list of exam objectives on Oracle’s website (the complete numbered list of exam objectives is given in table 2 in the Introduction). 4.2 Creating generic entities [4.1] Create a generic class On the exam, you’ll be tested on how to create generic classes, interfaces, and methods—within generic and nongeneric classes or interfaces. Figure 3 An example of the beginning of a section, identifying the exam objective that it covers Licensed to Mark Watson ABOUT THIS BOOK xxvii Exam tips Each chapter provides multiple exam tips to re-emphasize the points that are the most confusing, overlooked, or frequently answered incorrectly by candidates and that therefore require special attention for the exam. Figure 4 shows an example. EXAM TIP A type argument must be passed to the type parameter of a base class. You can do so while extending the base class or while instantiating the derived class. Figure 4 Example of an exam tip; they occur multiple times in a chapter Notes All chapters also include multiple notes, which draw your attention to points that should be noted while you’re preparing for the exam. Figure 5 shows an example. NOTE Though the exam might not include explicit questions on the contents of a class file after type erasure, it will help you to understand generics better and answer all questions on generics. Figure 5 Example note Sidebars Sidebars contain information that may not be directly relevant to the exam but that is related to it. Figure 6 shows an example. Using instanceof versus getClass in method equals() Using instanceof versus getClass is a common subject of debate about proper use and object orientation in general (including performance aspects, design patterns, and so on). Though important, this discussion is beyond the scope of this book. If you’re interested in further details, refer to Josh Bloch’s book Effective Java. Figure 6 Example sidebar Licensed to Mark Watson ABOUT THIS BOOK xxviii Images I’ve used a lot of images in the chapters for an immersive learning experience. I believe that a simple image can help you understand a concept quickly, and a little humor can help you to retain information longer. Simple images are used to draw your attention to a particular line of code (as shown in figure 7). Calling method 1 Calling method 2 public static Singleton getInstance() { if (anInstance == null) anInstance = new Singleton() ; return anInstance; } Create new Singleton object Figure 7 An example image that draws your attention to a particular line of code As shown in figure 8, I’ve used pictorial representation to aid better understanding of how Java concepts work. class Outer { class Inner{} Code added before byte code generation } 1 private final Outer this$0; Inner (Outer outer){ this$0 = outer; } In 2 Out Java compiler } 3 4 class Outer { class Inner{ In Out Outer.class Outer$Inner.class Figure 8 An example of pictorial representation of how the compiler handles data in an array Licensed to Mark Watson ABOUT THIS BOOK xxix To reinforce important points and help you retain them longer, a little humor has been added using comic strips (as in figure 9). If we are in love… we must must reside at the same address. if x.equals(y)==true x.hashCode()== y.hashCode() must be true Before marriage y x If we are not not in love… we might might or might not reside at the same address. if x.equals(y)==false x.hashCode() and y.hashCode() can be same or different Post breakup.... y x Figure 9 An example of a little humor to help you remember that the finally block always executes I’ve also used images to group and represent information for quick reference. Figure 10 shows an example of a rather raw form of the UML diagram that you may draw on an erasable board while taking your exam to represent an IS-A relationship between classes and interfaces. I strongly recommend that you try to create a few of your own figures like these. An image can also add more meaning to a sequence of steps explained in the text. For example, figure 11 seems to bring the process of adding and removing items to an ArrayList to life by showing placement of the existing items at each step. Again, try a few of your own. It’ll be fun! Movable Animal Cow Hunter Herbivore Goat Carnivore Lion Tiger Figure 10 An example of grouping and representing information for quick reference Licensed to Mark Watson www.allitebooks.com ABOUT THIS BOOK xxx Figure 11 An example image showing how existing elements are placed when items are added to or removed from an ArrayList The exam requires that you know multiple methods from collection classes, File I/O, NIO.2, concurrency, and others. The number of these methods can be overwhelming, but grouping these methods according to their functionality can make this task a lot more manageable. Figure 12 shows an example of an image that groups methods of the Queue class used to work with Deque as FIFO. 0 1 2 3 4 5 6 7 head tail Remove elements remove Query elements Add elements add(E) offer(E) element peer Query and remove poll Figure 12 An example image showing Queue methods used to work with Deque as a FIFO data structure Licensed to Mark Watson ABOUT THIS BOOK xxxi String processing expressions can be hard to comprehend. Figure 13 is an example of an image that can help you understand the strings that match a regular expression. Target string t h e l e a t h e r i n t h e i r c o a t m a d e h e r s e e t h e 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 Regex \Bthe Match a nonword boundary followed by “the” Matching result t h e l e a t h e r i n t h e i r c o a t m a d e h e r s e e t h e 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 Figure 13 Example of image showing the strings that match a regex pattern In multithreading, the same code can be executed by multiple threads. Such code can be difficult to comprehend. Figure 14 is an example of an image that clearly shows how the variable values of book:Book might be modified by multiple threads. book:Book task1 title = "Java" copiesSold = 0 book:Book copiesSold = 0+1 title = "Java" copiesSold = 1 book:Book task2 title = "Java" copiesSold = 0 book:Book copiesSold = 0+1 title = "Java" copiesSold = 1 book:Book task3 title = "Java" copiesSold = 0 book:Book copiesSold = 0–1 Time Figure 14 An example of how interleaving threads can lead to incorrect results Licensed to Mark Watson title = "Java" copiesSold = –1 ABOUT THIS BOOK xxxii Twist in the Tale exercises Each chapter includes a few Twist in the Tale exercises. For these exercises, I’ve tried to use modified code from the examples already covered in a chapter, and the “Twist in the Tale” title refers to modified or tweaked code. These exercises highlight how even small code modifications can change the behavior of your code. They should encourage you to carefully examine all of the code on the exam. My main reason for including these exercises is that on the real exam you may be asked to answer more than one question that seems exactly the same as another. But upon closer inspection, you’ll realize that these questions differ slightly, and that these differences change the behavior of the code and the correct answer option. The answers to all of the Twist in the Tale exercises are given in the appendix. Review notes When you’re ready to take your exam, don’t forget to reread the review notes a day before or on the morning of the exam. These notes contain important points from each chapter as a quick refresher. Exam questions Each chapter concludes with a set of sample exam questions. These follow the same pattern as the real exam questions. Attempt these exam questions after completing a chapter. Answers to exam questions The answers to all exam questions provide detailed explanations, including why options are correct or incorrect. Mark your incorrect answers and identify the sections that you need to reread. If possible, draw a few diagrams—you’ll be amazed at how much they can help you retain the concepts. Give it a try—it’ll be fun! This book online More information and a bonus chapter consisting of a mock exam can be found online at www.manning.com/gupta2. Author Online The purchase of this book includes free access to a private web forum run by Manning Publications, where you can make comments, ask technical questions, and receive help from the author and from other users. To access the forum and subscribe to it, point your web browser to www.manning.com/gupta2. This page provides information on how to get on the forum once you are registered, what kind of help is available, and the rules of conduct on the forum. Licensed to Mark Watson ABOUT THIS BOOK xxxiii Manning’s commitment to our readers is to provide a venue where a meaningful dialogue between individual readers and between readers and the author can take place. It is not a commitment to any specific amount of participation on the part of the author, whose contribution to the forum remains voluntary (and unpaid). We suggest you try asking the author some challenging questions lest her interest stray! The Author Online forum and the archives of previous discussions will be accessible from the publisher’s website as long as the book is in print. About the author Mala Gupta is passionate about making people employable by bridging the gap between their existing and required skills. In her quest to fulfill this mission, she is authoring books to help IT professionals and students on industry-recognized Oracle Java certifications. Mala has a master’s degree in computer applications along with multiple other certifications from Oracle. With over a decade and a half of experience working in IT as a developer, architect, trainer, and mentor, she has worked with international training and software services organizations on various Java projects. She is experienced in mentoring teams on technical and process skills. She is the founder and lead mentor of a portal (www.ejavaguru.com) that has offered Java courses for Oracle certification since 2006. Mala is a firm believer in creativity as an essential life skill. To popularize the importance of creativity, innovation, and design in life, she started “KaagZevar” (www.facebook.com/KaagZevar)—a platform to nurture design and creativity in life. About the cover illustration The figure on the cover this book is captioned “The habit of a French merchant in 1700.” The illustration is taken from Thomas Jefferys’ A Collection of the Dresses of Different Nations, Ancient and Modern (four volumes), London, published between 1757 and 1772. The title page states that these are hand-colored copperplate engravings, heightened with gum arabic. Thomas Jefferys (1719–1771) was called “geographer to King George III.” An English cartographer who was the leading map supplier of his day, Jefferys engraved and printed maps for government and other official bodies and produced a wide range of commercial maps and atlases, especially of North America. His work as a mapmaker sparked an interest in local dress customs of the lands he surveyed and mapped, which are brilliantly displayed in this four-volume collection. Fascination with faraway lands and travel for pleasure were relatively new phenomena in the late eighteenth century, and collections such as this one were popular, introducing both the tourist as well as the armchair traveler to the inhabitants of other countries. The diversity of the drawings in Jefferys’ volumes speaks vividly of the uniqueness and individuality of the world’s nations some 200 years ago. Dress codes have changed since then, and the diversity by region and country, so rich at the time, has faded away. It is now hard to tell the inhabitants of one continent apart from Licensed to Mark Watson xxxiv ABOUT THIS BOOK another. Perhaps, trying to view it optimistically, we have traded cultural and visual diversity for a more varied personal life. Or a more varied and interesting intellectual and technical life. At a time when it is hard to tell one computer book from another, Manning celebrates the inventiveness and initiative of the computer business with book covers based on the rich diversity of regional life of two centuries ago, brought back to life by Jefferys’ pictures. Licensed to Mark Watson Introduction This introduction covers ■ Introduction to the Oracle Certified Professional (OCP) Java SE 7 Programmer II certification (exam number 1Z0-804) ■ Importance of OCP Java SE 7 Programmer II certification ■ Detailed exam objectives, mapped to book chapters ■ FAQ on exam preparation and on taking the exam ■ Introduction to the testing engine used for the exam This book is intended specifically for individuals who wish to earn the Oracle Certified Professional (OCP) Java SE 7 Programmer II certification (exam number 1Z0-804). It assumes that you have practical experience of working with Java. If you are completely new to Java or to object-oriented languages, I suggest that you start your journey with an entry-level book and then come back to this one. 1 Licensed to Mark Watson 2 Introduction Disclaimer The information in this chapter is sourced from Oracle.com, public websites, and user forums. Input has been taken from real people who have earned Java certification, including the author. All efforts have been made to maintain the accuracy of the content, but the details of the exam—including its objectives, pricing, pass score, total number of questions, and maximum duration—are subject to change per Oracle’s policies. The author and publisher of the book shall not be held responsible for any loss or damage accrued due to any information contained in this book or due to any direct or indirect use of this information. Introduction to OCP Java SE 7 Programmer II certification (1Z0-804) The Oracle Certified Professional Java SE 7 Programmer II certification exam (1Z0804) covers intermediate and advanced concepts of Java programming, such as the importance of threads, concurrency, localization, JDBC, String processing, and design patterns. This exam is the second of the two steps in earning the title of OCP Java SE 7 Programmer. The first step is to earn the OCA Java SE 7 Programmer I certification (1Z0-803). Though you can write the exams 1Z0-803 and 1Z0-804 in any order to earn the title of OCP Java SE 7 Programmer, it is highly recommended that you write exam 1Z0-803 before exam 1Z0-804. Exam 1Z0-803 covers basics of Java and exam 1Z0-804 covers advanced Java topics. NOTE This exam certifies that an individual possesses strong practical skills in intermediate and advanced Java programming language concepts. Table 1 lists the details of this exam. Table 1 Details for OCP Java SE 7 Programmer II exam (1Z0-804) Exam number 1Z0-804 Java version Based on Java version 7 Number of questions 90 Passing score 65% Time duration 150 minutes Pricing US $245 Type of questions Multiple-choice The importance of the OCP Java SE 7 Programmer II certification Real, on-the-job projects need you to understand and work with multiple basic and advanced concepts. Apart from covering the finer details of basic Java-like class design, it covers advanced Java topics like threading, concurrency, localization, File I/O, string processing, exception handling, assertions, collections API, and design patterns. This Licensed to Mark Watson 3 Introduction to OCP Java SE 7 Programmer II certification (1Z0-804) certification establishes your expertise with these topics, increasing your prospects for better projects, jobs, remuneration, responsibilities, and designations. The OCP Java SE 7 Programmer II exam (1Z0-804) is an entry-level exam in your Java certification roadmap, as shown in figure 1. This exam is a prerequisite for most of the other Professional and Expert Oracle certifications in Java. The dashed lines and arrows in the figure depict the prerequisites for certifications. Associate Professional Java SE 7 Java SE 7 Expert Master Java SE 6 Developer Java SE 5/6 Java SE 6/5 Exam covered by book Java EE 5 Web Component Developer Java EE 6 Web Component Developer Java EE 5 Business Component Developer Java EE 6 Enterprise JavaBeans Developer Java SE Java EE 5 Enterprise Architect Java EE 6 Enterprise Architect Java EE Java EE 5 Web Services Developer Java EE 6 Web Services Developer Java EE 6 Web JavaServer Faces Developer Java EE 6 Java Persistence API Developer Java ME Mobile Application Developer Java ME Increasing difficulty level Figure 1 The OCP Java SE 7 Programmer II certification (1Z0-804) is an entry-level certification in the Java certification roadmap. It’s a prerequisite for writing most of the other Professional and Expert certifications in Java. Licensed to Mark Watson 4 Introduction As shown in figure 1, the Java certification tracks are offered under the categories Associate, Professional, Expert, and Master. Comparing the OCA Java SE 7 Programmer I (1Z0-803) and OCP Java SE 7 Programmer II (1Z0-804) exams The confusion about these two exams is due to the similarity in their names, but these are separate exams. Starting with Java 7, Oracle has raised the bar to earn the title of Oracle Certified Professional Java SE 7 Programmer, which now requires successfully completing the following two exams: ■ OCA Java SE 7 Programmer I (exam number: 1Z0-803) ■ OCP Java SE 7 Programmer II (exam number: 1Z0-804) The OCA Java SE 7 Programmer certification is designed for individuals who possess basic skills in the Java programming language. Exam 1Z0-803 covers comparatively basic Java language features, such as data types, operators, decision constructs, arrays, methods, inheritance, and exception handling. Complete exam objectives, mapped to book chapters, and readiness checklist Table 2 shows the complete list of exam objectives for the OCP Java SE 7 Programmer II exam, which was taken from Oracle’s website. All the objectives are mapped to the book’s chapters and the section numbers that cover them. Table 2 Exam objectives and subobjectives mapped to chapter and section numbers Exam objective as per Oracle’s website Covered in chapter/ section 11 Java class design Chapter 1 11.1 Use access modifiers: private, protected, and public Section 1.1 11.2 Override methods Section 1.3 11.3 Overload constructors and methods Section 1.2 11.4 Use the instanceof operator and casting Section 1.5 11.5 Use virtual method invocation Section 1.3 11.6 Override the hashCode, equals, and toString methods from the Object class to improve the functionality of your class Section 1.4 11.7 Use package and import statements Section 1.6 12 Advanced class design Chapter 2 12.1 Identify when and how to apply abstract classes Section 2.1 12.2 Construct abstract Java classes and subclasses Section 2.1 12.3 Use the static and final keywords Section 2.2 Licensed to Mark Watson Introduction to OCP Java SE 7 Programmer II certification (1Z0-804) Table 2 Exam objectives and subobjectives mapped to chapter and section numbers (continued) Exam objective as per Oracle’s website Covered in chapter/ section 12.4 Create top-level and nested classes Section 2.4 12.5 Use enumerated types Section 2.3 13 Object-oriented design principles Chapter 3 13.1 Write code that declares, implements, and/or extends interfaces Section 3.1 13.2 Choose between interface inheritance and class inheritance Section 3.2 13.3 Apply cohesion, low-coupling, IS-A, and HAS-A principles Sections 3.3, 3.4 13.4 Apply object composition principles (including HAS-A relationships) Section 3.5 13.5 Design a class using the Singleton design pattern Section 3.7 13.6 Write code to implement the Data Access Object (DAO) pattern Section 3.9 13.7 Design and create objects using a Factory pattern Section 3.8 14 Generics and collections Chapter 4 14.1 Create a generic class Section 4.2 14.2 Use the diamond for type inference Section 4.3 14.3 Analyze the interoperability of collections that use raw types and generic types Section 4.4 14.4 Use wrapper classes, autoboxing, and unboxing Sections 4.11, 4.12 14.5 Create and use List, Set, and Deque implementations Section 4.7 14.6 Create and use Map implementations Section 4.8 14.7 Use java.util.Comparator and java.lang.Comparable Section 4.9 14.8 Sort and search arrays and lists Section 4.10 15 String processing Chapter 5 15.1 Search, parse, and build strings (including Scanner, StringTokenizer, StringBuilder, String, and Formatter) Section 5.1 15.2 Search, parse, and replace strings by using regular expressions, using expression patterns for matching limited to: . (dot), * (star), + (plus), ?, \d, \D, \s, \S, \w, \W, \b, \B, [], () Sections 5.1, 5.2 15.3 Format strings using the formatting parameters: %b, %c, %d, %f, and %s in format strings Section 5.3 16 Exceptions and assertions Chapter 6 16.1 Use throw and throws statements Section 6.1 16.2 Use the try statement with multi-catch and finally clauses Section 6.4 Licensed to Mark Watson www.allitebooks.com 5 6 Introduction Table 2 Exam objectives and subobjectives mapped to chapter and section numbers (continued) Exam objective as per Oracle’s website Covered in chapter/ section 16.3 Develop code that uses try-with-resources statements Section 6.5 16.4 Create custom exceptions Section 6.2 16.5 Test invariants by using assertions Section 6.6 17 Java I/O fundamentals Chapter 7 17.1 Read and write data from the console Section 7.5 17.2 Use streams to read from and write to files by using classes in the java.io package including BufferedReader, BufferedWriter, File, FileReader, FileWriter, DataInputStream, DataOutputStream, ObjectOutputStream, ObjectInputStream, and PrintWriter Sections 7.2, 7.3, 7.4 18 Java file I/O (NIO.2) Chapter 8 18.1 Operate on file and directory paths with the Path class Section 8.1 18.2 Check, delete, copy, or move a file or directory with the Files class Section 8.2 Read and change file and directory attributes, focusing on the Section 8.3 18.3 BasicFileAttributes, DosFileAttributes, and PosixFileAttributes interfaces 18.4 Recursively access a directory tree using the DirectoryStream and FileVisitor interfaces Section 8.4 18.5 Find a file with the PathMatcher interface Section 8.5 18.6 Watch a directory for changes with the WatchService interface Section 8.6 19 Building database applications with JDBC Chapter 9 19.1 Describe the interfaces that make up the core of the JDBC API (including Driver, Connection, Statement, and ResultSet) and their relationships to provider implementations Section 9.2 19.2 Identify the components required to connect to a database using the DriverManager class (including the JDBC URL) Section 9.3 19.3 Submit queries and read results from the database (including creating statements, returning result sets, iterating through the results, and properly closing result sets, statements, and connections) Section 9.4 19.4 Use JDBC transactions (including disabling auto-commit mode, committing and rolling back transactions, and setting and rolling back to savepoints) Section 9.5 19.5 Construct and use RowSet objects using the RowSetProvider class and the RowSetFactory interface Section 9.6 Licensed to Mark Watson 7 FAQ Table 2 Exam objectives and subobjectives mapped to chapter and section numbers (continued) Exam objective as per Oracle’s website Covered in chapter/ section 19.6 Create and use PreparedStatement and CallableStatement objects Section 9.7 10 Threads Chapter 10 10.1 Create and use the Thread class and the Runnable interface Section 10.1 10.2 Manage and control thread lifecycle Section 10.2 10.3 Synchronize thread access to shared data Section 10.3 10.4 Identify code that may not execute correctly in a multi-threaded environment Section 10.4 11 Concurrency Chapter 11 11.1 Use collections from the java.util.concurrent package with a focus on the advantages over and differences from the traditional java.util collections Section 11.1 11.2 Use Lock, ReadWriteLock, and ReentrantLock classes in the java.util.concurrent.locks package to support lockfree, thread-safe programming on single variables Section 11.2 11.3 Use Executor, ExecutorService, Executors, Callable, and Future to execute tasks using thread pools Section 11.3 11.4 Use the parallel fork/join framework Section 11.4 12 Localization Chapter 12 12.1 Read and set the locale by using the Locale object Section 12.2 12.2 Build a resource bundle for each locale Section 12.2 12.3 Call a resource bundle from an application Section 12.2 12.4 Format dates, numbers, and currency values for localization with the NumberFormat and DateFormat classes (including number format patterns) Section 12.3 12.5 Describe the advantages of localizing an application Section 12.1 12.6 Define a locale using language and country codes Section 12.1 FAQ You might be anxious when you start your exam preparation or even think about getting certified. This section can help calm your nerves by answering frequently asked questions on exam preparation and on writing the exam. Licensed to Mark Watson 8 Introduction FAQ on exam preparation This sections answers frequently asked questions on how to prepare for the exam, including the best approach, study material, preparation duration, and how to test self-readiness. WILL THE EXAM DETAILS EVER CHANGE FOR THE OCP JAVA SE 7 PROGRAMMER II EXAM? Oracle can change the exam details for a certification even after the certification is made live. The changes can be made to any of its details, like exam objectives, pricing, exam duration, exam questions, and others. In the past, Oracle has made similar changes to certification exams. Such changes may not be major, but it is always advisable to check Oracle’s website for the latest exam information when you start your exam preparation. WHAT IS THE BEST WAY TO PREPARE FOR THIS EXAM? Generally, candidates use a combination of resources, such as books, online study materials, articles on the exam, free and paid mock exams, and training to prepare for the exam. Different combinations work best for different people, and there is no one perfect formula for preparation. Select the method—training or self-study—that works best for you. Combine it with a lot of code practice and mock exams. HOW DO I KNOW WHEN I AM READY FOR THE EXAM? You can be sure about your exam readiness by consistently getting a good score on the mock exams. Generally, a score of 80% and above on approximately 7 mock exams (the more the better) attempted consecutively will assure you of a similar score on the real exam. HOW MANY MOCK TESTS SHOULD I ATTEMPT BEFORE THE REAL EXAM? Ideally, you should attempt at least five complete mock exams before you attempt the real exam. The more the better! I HAVE TWO–FOURS YEARS’ EXPERIENCE WORKING WITH JAVA. DO I STILL NEED TO PREPARE FOR THIS CERTIFICATION? There is a difference between the practical knowledge of having worked with Java and the knowledge required to pass this certification exam. The authors of the Java certification exams employ multiple tricks to test your knowledge. Hence, you need a structured preparation and approach to succeed on the certification exam. WHAT IS THE IDEAL TIME REQUIRED TO PREPARE FOR THE EXAM? The preparation time frame mainly depends on your experience with Java and the amount of time that you can spend to prepare yourself. On average, you will require approximately 200 hours of study over two or three months to prepare for this exam. Again, the number of study hours required depends on individual learning curves and backgrounds. It’s important to be consistent with your exam preparation. You cannot study for a month and then restart after, say, a gap of a month or more. Licensed to Mark Watson FAQ 9 DO I NEED TO COMPLETE ANY TRAINING FROM ORACLE? Though Oracle requires candidates to complete specific Oracle training programs for a few of its certification courses, it isn’t mandatory to complete any training from Oracle for this certification. DOES THIS EXAM INCLUDE ANY UNSCORED QUESTIONS? A few of the questions that you write on any Oracle exam may be marked unscored. Oracle’s policy states that while writing an exam, you won’t be informed whether a question will be scored. You may be surprised to learn that as many as 10 out of the 90 questions on the OCP Java SE 7 Programmer II exam may be unscored. Even if you answer a few questions incorrectly, you stand a chance of scoring 100%. Oracle regularly updates its question bank for all its certification exams. These unscored questions may be used for research and to evaluate new questions that can be added to an exam. CAN I START MY EXAM PREPARATION WITH THE MOCK EXAMS? If you are quite comfortable with the advanced Java language features, then yes, you can start your exam preparation with the mock exams. This will also help you to understand the types of questions to expect on the real certification exam. But if you have little or no experience working with advanced Java concepts, I don’t advise you to start with the mock exams. The exam authors often use a lot of tricks to evaluate a candidate on the real certification exam. Starting your exam preparation with mock exams will only leave you confused about the Java concepts. SHOULD I REALLY BOTHER GETTING CERTIFIED? Yes, you should, for the simple reason that employers bother about the certification of employees. Organizations prefer a certified Java developer over a noncertified Java developer with similar IT skills and experience. The certification can also get you a higher paycheck than uncertified peers with comparable skills. FAQ on taking the exam This section contains a list of frequently asked questions related to exam registration, the exam coupon, do’s and don’t’s while taking the exam, and exam retakes. WHERE AND HOW DO I WRITE THIS EXAM? You can write this exam at an Oracle Testing Center or Pearson VUE Authorized Testing Center. To sit for the exam, you must register and purchase an exam voucher. The following options are available: ■ ■ ■ Register for the exam and pay Pearson VUE directly. Purchase an exam voucher from Oracle and register at Pearson VUE to take the exam. Register at an Oracle Testing Center. Look for the nearest testing centers in your area, register yourself, and schedule an exam date and time. Most of the popular computer training institutes also have a Licensed to Mark Watson 10 Introduction testing center on their premises. You can locate a Pearson VUE testing site at www.pearsonvue.com/oracle/, which contains detailed information on locating testing centers and scheduling or rescheduling an exam. At the time of registration, you’ll need to provide the following details along with your name, address, and contact numbers: ■ ■ ■ ■ Exam title and number (OCP Java SE 7 Programmer II, 1Z0-804) Any discount code that should be applied during registration Oracle Testing ID/Candidate ID, if you have written any other Oracle/Sun certification exam(s) Your OPN Company ID (If your employer is in the Oracle Partner Network, you can find out the company ID and use any available discounts on the exam fee.) HOW LONG IS THE EXAM COUPON VALID FOR? Each exam coupon is printed with an expiration date. Beware of any discounted coupons that come with an assurance that they can be used past the expiration date. CAN I REFER TO NOTES OR BOOKS WHILE WRITING THIS EXAM? You can’t refer to any books or notes while writing this exam. You are not allowed to carry any blank paper for rough work or even your mobile phone inside the testing cubicle. WHAT IS THE PURPOSE OF MARKING A QUESTION WHILE WRITING THE EXAM? By marking a question, you can manage your time efficiently. Don’t spend a lot of time on a single question. You can mark a difficult question to defer answering it while writing your exam. You have an option to review answers to the marked questions at the end of the exam. Also, navigating from one question to another using Back and Next buttons is usually time-consuming. If you are unsure of an answer, mark it and review it at the end. CAN I WRITE DOWN THE EXAM QUESTIONS AND BRING THEM BACK WITH ME? No. The exam centers no longer provide sheets of paper for the rough work that you may need to do while taking the exam. The testing center will provide you with either erasable or nonerasable boards. If you’re provided with a nonerasable board, you may request another one if you need it. Oracle is quite particular about certification candidates distributing or circulating the memorized questions in any form. If Oracle finds out that this is happening, it may cancel a candidate’s certificate, bar that candidate forever from writing any Oracle certification, inform the employer, or take legal action. WHAT HAPPENS IF I COMPLETE THE EXAM BEFORE OR AFTER THE TOTAL TIME? If you complete the exam before the total exam time has elapsed, review your answers and click the Submit or finish button. If you have not clicked the Submit button and you use up all the exam time, the exam engine will no longer allow you to modify any of the exam answers and will present the screen with the Submit button. Licensed to Mark Watson The testing engine used in the exam 11 WILL I RECEIVE MY SCORE IMMEDIATELY AFTER THE EXAM? No, you won’t. When you click the Submit exam button, the screen will inform you that your exam results will be available in an hour. Usually Oracle sends you an email when the results can be accessed online. Even if you don’t receive an email from Oracle, you could log in and check your result. The result includes your score on each exam objective. The certificate itself will arrive via mail within six to eight weeks. WHAT HAPPENS IF I FAIL? CAN I RETAKE THE EXAM? It’s not the end of the world. Don’t worry if you fail. You can retake the exam after 14 days (and the world will not know it’s a retake). However, you cannot retake a passed exam to improve your score. Also, you cannot retake a beta exam. The testing engine used in the exam The UI of the testing engine used for the certification exam is quite simple. (You could even call it primitive, compared to today’s web, desktop, and smartphone applications.) Before you can start the exam, you will be required to accept the terms and conditions of the Oracle Certification Candidate Agreement. Your computer screen will display all these conditions and give you an option to accept the conditions. You can proceed with writing the exam only if you accept these conditions. Here are the features of the testing engine used by Oracle: ■ ■ ■ ■ ■ The engine UI is divided into three sections. The UI of the testing engine is divided into the following three segments: – Static upper section—Displays question number, time remaining, and a checkbox to mark a question for review. – Scrollable middle section—Displays the question text and the answer options. – Static bottom section—Displays buttons to display the previous question, display the next question, end the exam, and review marked questions. Each question is displayed on a separate screen. The exam engine displays one question on the screen at a time. It does not display multiple questions on a single screen, like a scrollable web page. All effort is made to display the complete question and answer options without scrolling, or with little scrolling. Code exhibit button. Many questions include code. Such questions, together with their answers, may require significant scrolling to be viewed. As this can be quite inconvenient, such questions include a Code Exhibit button that displays the code in a separate window. Mark questions to be reviewed. The question screen displays a check box with the text “Mark for review” at the top-left corner. A question can be marked using this option. The marked questions can be reviewed at the end of the exam. Buttons to display previous and next questions. The test includes buttons to display previous and next questions within the bottom section of the testing engine. Licensed to Mark Watson 12 Introduction ■ ■ ■ ■ Buttons to end the exam and review marked questions. The engine displays buttons to end the exam and to review the marked questions in the bottom section of the testing engine. Remaining time. The engine displays the time remaining for the exam at the top right of the screen. Question number. Each question displays its serial number. Correct number of answer options. Each question displays the correct number of options that should be selected from multiple options. On behalf of all at Manning Publications, I wish you good luck and hope that you score very well on your exam. Licensed to Mark Watson Java class design Exam objectives covered in this chapter What you need to know [1.1] Use access modifiers: private, protected, and public How to use appropriate access modifiers to design classes How to limit accessibility of classes, interfaces, enums, methods, and variables by using the appropriate access modifiers The correct combination of access modifiers and the entities (classes, interfaces, enums, methods, and variables) to which they can be applied The implications of modifying the access modifier of a Java entity [1.2] Override methods The conditions and requirements that make a subclass override a base class method How to differentiate among overloaded, overridden, and hidden methods [1.3] Overload constructors and methods The need and right rules to overload constructors and methods [1.4] Use the instanceof operator and casting Understand the right use of the instanceof operator, and implicit and explicit object casting and their implications Compilation errors and runtime exceptions associated with the use of the instanceof operator and casting [1.5] Use virtual method invocation The methods that can and can’t be invoked virtually 13 Licensed to Mark Watson 14 CHAPTER 1 Java class design Exam objectives covered in this chapter What you need to know [1.6] Override methods from the Object class to improve the functionality of your class The need to override methods from class Object—differentiate correct, incorrect, appropriate, and inappropriate overriding [1.7] Use package and import statements How to package classes and use package, import, and static import statements Classes and interfaces are building blocks of an application. Efficient and effective class design makes a significant impact on the overall application design. Imagine if, while designing your classes, you didn’t consider effective packaging, correct overloaded or overridden methods, or access protection—you might lose on extensibility, flexibility, and usability of your classes. For example, if you didn’t override methods hashCode() and equals() correctly in your classes, your seemingly “equal” objects might not be considered equal by collection classes like HashSet or HashMap. Or, say, imagine if you didn’t use the right access modifiers to protect your classes and their members, they could be subject to unwanted manipulation by other classes from the same or different packages. The creation of overloaded methods is another domain, which is an important class design decision. It eases instance creation and use of methods. Class design decisions require an insight into understanding correct and appropriate implementation practices. When armed with adequate information you’ll be able to select the best practices and approach to designing your classes. The topics covered in this chapter will help you design better classes by taking you through multiple examples. This chapter covers ■ ■ ■ ■ ■ ■ ■ Access modifiers Method overloading Method overriding Virtual method invocation Use of the instanceof operator and casting Override methods from class Object to improve the functionality of your class How to create packages and use classes from other packages Let’s get started with how to control access to your classes and their members, using access modifiers. Licensed to Mark Watson 15 Java access modifiers 1.1 Java access modifiers [1.1] Use access modifiers: private, protected, and public When you design applications and create classes, you need to answer multiple questions: ■ ■ How do I restrict other classes from accessing certain members of a class? How do I prevent classes from modifying the state of objects of a class, both within the same and separate packages? Java access modifiers answer all these questions. Access modifiers control the accessibility of a class or an interface, including its members (methods and variables), by other classes and interfaces within the same or separate packages. By using the appropriate access modifiers, you can limit access to your class or interface, and its members. Access modifiers can be applied to classes, interfaces, and their members (instance and class variables and methods). Local variables and method parameters can’t be defined using access modifiers. An attempt to do so will prevent the code from compiling. In this section, we’ll cover all of the access modifiers—public, protected, and private—as well as default access, which is the result when you don’t use an access modifier. You’ll also discover the effects of changing the access levels of existing types on other code. Access modifiers are also covered in the OCA Java SE 7 Programmer I exam (1Z0-803). If you’ve written this exam recently, then perhaps you might like to skip sections 1.1.1–1.1.4. NOTE To understand all of these access modifiers, we’ll use the same set of classes: Book, CourseBook, Librarian, StoryBook, and House. Figure 1.1 depicts these classes using UML notation. Classes Book, CourseBook, and Librarian are defined in the package library. Classes StoryBook and House are defined in the package building. Classes StoryBook and CourseBook (defined in separate packages) extend class Book. Using these classes, library building < > Book StoryBook Librarian House < > CourseBook Figure 1.1 A set of classes and their relationships to help understand access modifiers Licensed to Mark Watson www.allitebooks.com 16 CHAPTER 1 Java class design library building < > Book StoryBook +isbn:String +printBook() House Librarian < > CourseBook Figure 1.2 Understanding the public access modifier you’ll see how the accessibility of a class and its members varies with different access modifiers, from unrelated to derived classes, across packages. As we cover each of the access modifiers, we’ll add a set of instance variables and a method to class Book with the relevant access modifier. 1.1.1 Public access modifier This is the least restrictive access modifier. Classes and interfaces defined using the public access modifier are accessible across all packages, from derived to unrelated classes. To understand the public access modifier, let’s define class Book as a public class and add a public instance variable (isbn) and a public method (printBook()) to it. Figure 1.2 shows the UML notation. Examine the following definition of class Book: package library; public class Book { public String isbn; public void printBook() {} } public class Book public variable isbn public method printBook() The public access modifier is said to be the least restrictive, so let’s try to access the public class Book and its public members from class House. We’ll use class House because House and Book are defined in separate packages and they’re unrelated. Class House doesn’t enjoy any advantages of being defined in the same package or being a derived class. Here’s the code for class House: package building; import library.Book; public class House { Licensed to Mark Watson 17 Java access modifiers public House() { Book book = new Book(); String value = book.isbn; book.printBook(); } Book is accessible to House } isbn is accessible to House printBook() is accessible to House In the preceding example, class Book and its public members—instance variable isbn and method printBook()—are accessible to class House. They’re also accessible to the other classes: StoryBook, Librarian, and CourseBook. Figure 1.3 shows the classes that can access a public class and its members. 1.1.2 Protected access modifier The members of a class defined using the protected access modifier are accessible to ■ ■ Classes and interfaces defined in the same package All derived classes, even if they’re defined in separate packages EXAM TIP Members of an interface are implicitly public. If you define interface members as protected, the interface won’t compile. Let’s add a protected instance variable author and method modifyTemplate() to class Book. Figure 1.4 shows the class representation. Same package Separate package Derived classes Unrelated classes Figure 1.3 Classes that can access a public class and its members library building < > Book StoryBook #author:String #modifyTemplate() House Librarian < > CourseBook Figure 1.4 Understanding the protected access modifier Licensed to Mark Watson 18 CHAPTER 1 Java class design Here’s the code for class Book (I’ve deliberately left out its public members because they aren’t required in this section): package library; public class Book { protected String author; protected void modifyTemplate(){} } protected variable author protected method modifyTemplate() Figure 1.5 illustrates how classes from the same and separate packages, derived classes, and unrelated classes access class Book and its protected members. building library package library; public class Book { protected string author; Can access < > protected void modifyTemplate(){} } Can access < > package library; package building; public class CourseBook extends Book { import library.Book; public class StoryBook extends Book{ public CourseBook(){ modifyTemplate(); } } Cannot access author="ABC"; public StoryBook(){ author="ABC"; modifyTemplate(); } } package library; package building; public class Librarian { import library.Book; public Librarian(){ public class House{ Book book = new Book(); book.author = "ABC"; public House(){ Can access Book book=new Book(); book.modifyTemplate(); book.author="ABC"; } book.modifyTemplate(); } } } Figure 1.5 Access of protected members of class Book in unrelated and derived classes, from the same and separate packages Licensed to Mark Watson 19 Java access modifiers Class House fails compilation for trying to access method modifyTemplate()and variable author, as follows: House.java:8: modifyTemplate()has protected access in library.Book book.modifyTemplate(); ^ A derived class inherits the protected members of its base class, irrespective of the packages in which they are defined. Notice that the derived classes CourseBook and StoryBook inherit class Book’s protected member variable author and method modifyTemplate(). If class StoryBook tries to instantiate Book using a reference variable and then tries to access its protected variable author and method modifyTemplate(), it won’t compile: package building; import library.Book; class StoryBook extends Book { StoryBook () { Book book = new Book(); String v = book.author; book.modifyTemplate(); } } Book and StoryBook defined in separate packages Protected members of Book aren’t accessible in StoryBook if accessed using an instance of Book. A concise but not too simple way of stating the previous rule is this: A derived class can inherit and access protected members of its base class, regardless of the package in which it’s defined. A derived class in a separate package can’t access protected members of its base class using reference variables. EXAM TIP Figure 1.6 shows the classes that can access protected members of a class or an interface. 1.1.3 Default access (package access) The members of a class defined without using any explicit access modifier are defined with package accessibility (also called default accessibility). The members with package access are only accessible to classes and interfaces defined in the same package. The default access is also referred to as package-private. Think of a package as your home, classes as rooms, and things in rooms as variables with default access. These things Using inheritance Same package Using reference variable Separate package Derived classes Unrelated classes Figure 1.6 Classes that can access protected members Licensed to Mark Watson 20 CHAPTER 1 Java class design aren’t limited to one room—they can be accessed across all the rooms in your home. But they’re still private to your home—you wouldn’t want them to be accessed outside your home. Similarly, when you define a package, you might want to make accessible members of classes to all the other classes across the same package. While the package-private access is as valid as the other access levels, in real projects, it often appears as the result of inexperienced developers forgetting to specify the access modifier of Java components. NOTE Let’s define an instance variable issueCount and a method issueHistory()with default access in class Book. Figure 1.7 shows the class representation with these new members. Here’s the code for class Book (I’ve deliberately left out its public and protected members because they aren’t required in this section): package library; public class Book { int issueCount; void issueHistory () {} } public class Book issueCount with default access issueHistory() with default access You can see how classes from the same package and separate packages, derived classes, and unrelated classes access class Book and its members (instance variable issueCount and method issueHistory()) in figure 1.8. Because classes CourseBook and Librarian are defined in the same package as class Book, they can access the members issueCount and issueHistory(). Because classes House and StoryBook aren’t defined in the same package as class Book, they can’t access the members issueCount and issueHistory(). Class StoryBook fails compilation with the following error message: StoryBook.java:6: issueHistory () is not public in library.Book; cannot be accessed from outside package book.issueHistory (); ^ library building < > Book StoryBook ~issueCount:int ~issueHistory() House Librarian < > CourseBook Figure 1.7 Understanding class representations for the default access Licensed to Mark Watson 21 Java access modifiers building library package library; public class Book { Can access int issueCount; Cannot access < > void issueHistory(){} Can access } < > package building; package library; import library.Book; public class CourseBook extends Book { public class StoryBook extends Book{ int c = issueCount; issueHistory(); } Cannot access public CourseBook(){ public StoryBook(){ int c = issueCount; issueHistory(); } } } package library; package building; public class Librarian { import library.Book; public Librarian(){ public class House{ Book b = new Book(); public House(){ int c = b.issueCount; Book b = new Book(); b.issueHistory(); int c = b.issueCount; } b.issueHistory(); } } } Figure 1.8 Access of members with default access to class Book in unrelated and derived classes from the same and separate packages Class House is unaware of the existence of issueHistory()—it fails compilation with the following error message: House.java:9: cannot find symbol symbol : method issueHistory () location: class building.House issueHistory (); DEFINING A CLASS BOOK WITH DEFAULT ACCESS What happens if you define a class with default access? What will happen to the accessibility of its members if the class itself has default (package) accessibility? Licensed to Mark Watson 22 CHAPTER 1 Java class design Can be accessed only by inhabitants of the island Far-away island inaccessble by air and water Figure 1.9 This Superfast Burgers cannot be accessed from outside the island because the island is inaccessible by air and water. Consider this situation: Assume that Superfast Burgers opens a new outlet on a beautiful island and offers free meals to people from all over the world, which obviously includes inhabitants of the island. But the island is inaccessible by all means (air and water). Would the existence of this particular Superfast Burger outlet make any sense to people who don’t inhabit the island? An illustration of this example is shown in figure 1.9. The island is like a package in Java, and the Superfast Burger outlet is like a class defined with default access. In the same way that the Superfast Burger outlet can’t be accessed from outside the island on which it exists, a class defined with default (package) access is visible and accessible only within the package in which it’s defined. It can’t be accessed from outside its package. Let’s redefine class Book with default (package) access as follows: package library; class Book { //.. class members } Book now has default access The behavior of class Book remains the same for classes CourseBook and Librarian, which are defined in the same package. But class Book can’t be accessed by classes House and StoryBook, which reside in a separate package. Let’s start with class House. Examine the following code: package building; import library.Book; public class House {} Book isn’t accessible in House Licensed to Mark Watson 23 Java access modifiers Same package Separate package Derived classes Unrelated classes Figure 1.10 Classes that can access members with default (package) access Class House fails compilation with the following error message: House.java:2: library.Book is not public in library; cannot be accessed from outside package import library.Book; Here’s the code of class StoryBook: package building; import library.Book; class StoryBook extends Book {} Book isn’t accessible in StoryBook StoryBook cannot extend Book Figure 1.10 shows which classes can access members of a class or an interface with default (package) access. Because a lot of programmers are confused about which members are made accessible by using the protected access modifier and no modifier (default), the following exam tip offers a simple and interesting rule to help you remember their differences. Default access can be compared to package-private (accessible only within a package) and protected access can be compared to package-private + kids (kids refers to derived classes). Kids can access protected members only by inheritance and not by reference (accessing members by using the dot operator on an object). EXAM TIP 1.1.4 The private access modifier The private access modifier is the most restrictive access modifier. The members of a class defined using the private access modifier are accessible only to them. For example, the internal organs of your body (heart, lungs, etc.) are private to your body. No one else can access them. It doesn’t matter whether the class or interface in question is from another package or has extended the class—private members aren’t accessible outside the class in which they’re defined. EXAM TIP Members of an interface are implicitly public. If you define interface members as private, the interface won’t compile. Licensed to Mark Watson 24 CHAPTER 1 Java class design library building < > Book StoryBook -countPages() #modifyTemplate() House Librarian < > CourseBook Figure 1.11 Understanding the private access modifier Let’s see the private members in action by adding a private method countPages() to class Book. Figure 1.11 depicts the class representation using UML. Examine the following definition of class Book: package library; class Book { private void countPages () {} protected void modifyTemplate(){ countPages (); } } Private method Only Book can access its own private method countPages() None of the classes defined in any of the packages (whether derived or not) can access the private method countPages(). But let’s try to access it from class CourseBook. I chose class CourseBook because both of these classes are defined in the same package, and class CourseBook extends class Book. Here’s the code of CourseBook: package library; class CourseBook extends Book { CourseBook () { countPages (); } } CourseBook extends Book CourseBook cannot access private method countPages() Because class CourseBook tries to access private members of class Book, it will not compile. Similarly, if any of the other classes (StoryBook, Librarian, or House) try to access private method countPages() of class Book, it will not compile. Figure 1.12 shows the classes that can access the private members of a class. For your real projects, it is possible to access private members of a class outside them, using Java Reflection. But Java Reflection isn’t on the exam. So don’t consider it when answering questions on the accessibility of private members. NOTE Licensed to Mark Watson 25 Java access modifiers Same package Separate package Derived classes Figure 1.12 No classes can access private members of another class. Unrelated classes 1.1.5 Access modifiers and Java entities Can every access modifier be applied to all the Java entities? The simple answer is no. Table 1.1 lists the Java entities and the access modifiers that can be used with them. Table 1.1 Java entities and the access modifiers that can be applied to them Entity name public protected private Top-level class, interface, enum ✓ ✗ ✗ Nested class, interface, enum ✓ ✓ ✓ Class variables and methods ✓ ✓ ✓ Instance variables and methods ✓ ✓ ✓ Method parameters and local variables ✗ ✗ ✗ What happens if you try to code the combinations for an X above? None of these combinations will compile. Here’s the code: protected class MyTopLevelClass {} private class MyTopLevelClass {} protected interface TopLevelInterface {} protected enum TopLevelEnum {} void myMethod(private int param) {} void myMethod(int param) { public int localVariable = 10; } Won’t compile—top-level class, interface, and enums can’t be defined with protected and private access. Won’t compile—method parameters and local variables can’t be defined using any explicit access modifiers. Watch out for these combinations on the exam. It’s simple to insert these small and invalid combinations in any code snippet and still make you believe that you’re being tested on a rather complex topic like threads or concurrency. Watch out for invalid combinations of a Java entity and an access modifier. Such code won’t compile. EXAM TIP Licensed to Mark Watson www.allitebooks.com 26 CHAPTER 1 Java class design Project status: code by Harry fails compilation I promise! I didn’t change any code! Harry Then how did this happen? Paul Figure 1.13 A change in the access modifier of a member of a class can break the code of other classes. 1.1.6 Effects of changing access modifiers for existing entities Shreya, a programmer, changed the access modifier of a member in her class, Book, and see what Harry (another programmer) had to go through the next morning (figure 1.13). Let’s analyze what happened. Why did Harry’s code break when Shreya changed her own code? As shown in figure 1.14, Harry’s class StoryBook extends class Book created by Shreya. Before the modifications, Harry’s class StoryBook accessed the protected member author from its parent class Book. But when Shreya modified the access modifier of the member author from protected to default access, it could no longer be accessed by class StoryBook because they reside in separate packages. So, even though Harry didn’t change his code, it didn’t compile. You can change the access modifier of a member in two ways: ■ ■ Accessibility is decreased—for example, a public member is made private Accessibility is increased—for example, a private member is made public WHEN ACCESSIBILITY OF AN ENTITY IS DECREASED (MORE RESTRICTIVE) As shown in figure 1.14, when an entity is made more restrictive, there are chances that other code that uses that entity might break. Impact of decreasing accessibility in real-life projects Decreasing the accessibility of entities can affect the overall application in a big way. This is especially important for designing APIs and maintaining software. Many Java developers make the mistake of carelessly decreasing the accessibility of methods or fields, which can result in access issues with other components in a system. WHEN ACCESSIBILITY OF AN ENTITY IS INCREASED (LESS RESTRICTIVE) There are no issues when an entity is made less restrictive, say, when access of an entity is changed from default to protected or public. With increased access, an Licensed to Mark Watson 27 Java access modifiers Before modification library building package library; public class Book { < > Can access protected String author; package building; import library.Book; Class StoryBook extends Book{ } {author = "Selvan";} } Shreya’s code Harry’s code After modification building library package library; public class Book { < > Can’t access String author; package building; import library.Book; Class StoryBook extends Book{ } {author = "Selvan";} } Shreya’s code Harry’s code Figure 1.14 Code before and after modification showing why Harry’s code failed to compile, even though he didn’t change a bit of it. entity may become visible to other classes, interfaces, and enums to which it wasn’t visible earlier. Apart from being an important exam topic, you’re sure to encounter issues related to access modifiers at your workplace in real projects. Let’s see whether you can spot a similar issue in the first “Twist in the Tale” exercise. About the “Twist in the Tale” exercises For these exercises, I’ve tried to use modified code from the examples already covered in the chapter. The “Twist in the Tale” title refers to modified or tweaked code. These exercises will help you understand how even small code modifications can change the behavior of your code. They should also encourage you to carefully examine all of the code on the exam. The reason for these exercises is that on the exam, you may be asked more than one question that seems to require the same answer. But on closer inspection, you’ll realize that the questions differ slightly, and this will change the behavior of the code and the correct answer option. All answers to “Twist in the Tale” exercises are in the appendix. Licensed to Mark Watson 28 CHAPTER 1 Java class design Twist in the Tale 1.1 Here are the classes written by Shreya and Harry (residing in separate source code files) that work without any issues: package library; public class Book { protected String author; } // Class written by Shreya package building; import library.Book; class StoryBook extends Book { { author = "Selvan"; } // Class written by Harry } On Friday evening, Shreya modified her code and checked it in to the organization’s version control system. Do you think Harry would be able to run his code without any errors when he checks out the modified code on Monday morning, and why? Here’s the modified code: package library; class Book { protected String author; } // Class written by Shreya package building; import library.Book; class StoryBook extends Book { { author = "Selvan"; } } // Class written by Harry In the next section, we’ll cover the need and semantics of defining overloaded methods. You can compare overloaded methods with any action that you might specify with multiple, different, or additional details. Let’s get started with understanding the need of defining overloaded methods. 1.2 Overloaded methods and constructors [1.3] Overload constructors and methods Overloaded methods are methods with the same name but different method parameter lists. In this section, you’ll learn how to create and use overloaded methods. Imagine that you’re delivering a lecture and need to instruct the audience to take notes using paper, a Smartphone, or a laptop—whichever is available to them for the day. One way to do this is to give the audience a list of instructions like ■ ■ ■ Take notes using paper. Take notes using Smartphones. Take notes using laptops. Licensed to Mark Watson Overloaded methods and constructors Unrelated methods Different names Figure 1.15 29 Overloaded methods Same names takeNotesUsingPaper takeNotes(Paper) takeNotesUsingSmartphone takeNotes(Smartphone) takeNotesUsingLaptop takeNotes(Laptop) Real-life examples of overloaded methods Another method is to instruct them to “take notes” and then provide them with the paper, a Smartphone, or a laptop they’re supposed to use. Apart from the simplicity of the latter method, it also gives you the flexibility to add other media on which to take notes (such as one’s hand, some cloth, or the wall) without needing to remember the list of all the instructions. This second approach—providing one set of instructions (with the same name) but a different set of input values—can be compared to overloaded methods in Java, as shown in figure 1.15. The implementation of the example shown in figure 1.15 in code is as follows: class Paper {} class Smartphone {} class Laptop {} class Lecture { void takeNotes(Paper paper) {} void takeNotes(Smartphone phone) {} void takeNotes(Laptop laptop) {} } Overloaded method— takeNotes() Overloaded methods are usually referred to as methods that are defined in the same class, with the same name, but with a different method argument list. A derived class can also overload the methods inherited from its base class as follows: class Paper {} class Smartphone {} class Laptop {} class Lecture { void takeNotes(Paper paper) {} void takeNotes(Smartphone phone) {} void takeNotes(Laptop laptop) {} } class Canvas {} class FineArtLecture extends Lecture { void takeNotes(Canvas canvas) {} } takeNotes() in FineArtLecture overloads takeNotes() from Lecture by specifying a different parameter list. Licensed to Mark Watson 30 CHAPTER 1 Java class design Overloaded methods make it easier to add methods with similar functionality that work with a different set of input values. Let’s work with an example from the Java API classes that we all use frequently: System.out.println(). Method println() accepts multiple types of method parameters: int intVal = 10; boolean boolVal = false; String name = "eJava"; Prints an int value System.out.println(intVal); System.out.println(boolVal); System.out.println(name); Prints a boolean value Prints a string value When you use method println(), you know that whatever you pass to it as a method argument will be printed to the console. Wouldn’t it be crazy to use methods like printlnInt(), printlnBool(), and printlnString() for the same functionality? I think so, too. Let’s examine in detail the method parameters passed to overloaded methods, their return types, and their access and nonaccess modifiers. The exam will test you on how you can define correct overloaded methods, which overloaded methods get invoked when you use a set of arguments, and also whether a compiler is unable to resolve the call. NOTE 1.2.1 Argument list Overloaded methods accept different lists of arguments. The argument lists can differ in terms of ■ ■ ■ The change in the number of parameters that are accepted The change in the type of the method parameters that are accepted The change in the positions of the parameters that are accepted (based on parameter type, not variable names) Let’s work with some examples to verify these points. CHANGE IN THE NUMBER OF METHOD PARAMETERS Overloaded methods that define a different number of method parameters are the simplest among all the method types. Let’s work with an example of an overloaded method, calcAverage(), which accepts a different count of method parameters: class Result { Two method double calcAverage(int marks1, int marks2) { arguments return (marks1 + marks2)/2; } double calcAverage(int marks1, int marks2, int marks3) { Three return (marks1 + marks2 + marks3)/3; method } arguments } Licensed to Mark Watson 31 Overloaded methods and constructors CHANGE IN THE TYPE OF METHOD PARAMETERS In the following example, the difference is in the argument list—due to the change in the type of parameters it accepts—to calculate the average of integer and decimal numbers: class Result { double calcAverage(int marks1, double marks2) { return (marks1 + marks2)/2; } double calcAverage(double marks1, double marks2) { return (marks1 + marks2)/2; } } Arguments— int and double Arguments— double and double When you define overloaded methods with object references as parameters, their classes might or might not share an inheritance relationship. When the classes don’t share an inheritance relationship, there isn’t any confusion with the version of the method that will be called: class Employee {} class Engineer extends Employee {} class CEO extends Employee {} class Travel { static String bookTicket(Engineer val) { return "economy class"; } static String bookTicket(CEO val) { return "business class"; } } Engineer and CEO aren’t in the same inheritance tree For the preceding code, if you call method bookTicket() by passing it a CEO object, it will call the method that accepts a parameter of type CEO—no confusion here. Now, what happens if you define overloaded methods that accept object references of classes which share an inheritance relationship? For example (modifications in code are in bold) class Employee {} class CEO extends Employee {} class Travel { static String bookTicket(Employee val) { return "economy class"; } static String bookTicket(CEO val) { return "business class"; } } Method parameters—CEO extends Employee Licensed to Mark Watson 32 CHAPTER 1 Java class design Which of these methods do you think would be called if you pass a CEO object to method bookTicket()? Can a CEO object be assigned to both CEO and Employee? class TravelAgent { public static void main(String... args) { System.out.println(Travel.bookTicket(new CEO())); } } Prints “business class” The preceding code calls overloaded method bookTicket()that accepts a CEO, because without any explicit reference variable, new CEO() is referred to using a CEO variable. Now, try to determine the output of the following code: class TravelAgent { public static void main(String... args) { Employee emp = new CEO(); System.out.println(Travel.bookTicket(emp)); } } Prints “economy class” The preceding code prints “economy class” and not “business class” because the type of the reference variable emp is Employee. The overloaded methods are bound at compile time and not runtime. To resolve the call to the overloaded methods, the compiler considers the type of variable that’s used to refer to an object. Calls to the overloaded methods are resolved during compilation. EXAM TIP Using the preceding Employee and CEO example, figure 1.16 shows a fun way to remember calls to the overloaded methods are resolved during compilation. Please book a ticket to Paris for our employee. Group secretary Figure 1.16 Sure! Travel desk Why didn’t you book business class? Because you were referred to as an employee. CEO Overloaded methods are resolved during compilation. Licensed to Mark Watson Travel desk 33 Overloaded methods and constructors For the overloaded method bookTicket() that defines the method parameter of either Engineer or CEO, watch out for exam questions that try to call it using a reference variable of Employee: class Employee {} class Engineer extends Employee {} class CEO extends Employee {} class Travel { static String bookTicket(Engineer val) { return "economy class"; } static String bookTicket(CEO val) { return "business class"; } public static void main(String args[]) { Employee emp = new CEO(); System.out.println(bookTicket(emp)); } } Accepts Engineer Accepts CEO Won’t compile—Travel doesn’t define method that accepts Employee CHANGE IN THE POSITIONS OF METHOD PARAMETERS The methods are correctly overloaded if they only change the positions of the parameters that are passed to them, as follows: double calcAverage(double marks1, int marks2) { return (marks1 + marks2)/2; } double calcAverage(int marks1, double marks2) { return (marks1 + marks2)/2; } Arguments— double and int Arguments— int and double Although you might argue that the arguments being accepted are the same, with only a difference in their positions, the Java compiler treats them as different argument lists. Therefore, the previous code is a valid example of overloaded methods. But an issue arises when you try to execute this method using values that can be passed to both versions of the overloaded method. In this case, the code in method main() will fail to compile: b Method parameters— class MyClass { double and int static double calcAverage(double marks1, int marks2) { return(marks1 + marks2)/2; Method } parameters— static double calcAverage(int marks1, double marks2) { int and double return(marks1 + marks2)/2; } Compiler can’t determine public static void main(String[] args) { overloaded calcAverage() calcAverage(2, 3); that should be called } } c d In the previous code, B defines the calcAverage() method, which accepts two method parameters: a double and an int. The code at c defines overloaded method Licensed to Mark Watson 34 CHAPTER 1 Java class design calcAverage(), which accepts two method parameters: first an int and then a double. Because an int literal value can be passed to a variable of type double, literal values 2 and 3 can be passed to both overloaded methods, declared at B and c. Because this method call is dubious, the code at d fails to compile, with the following message: MyClass.java:10: error: reference to calcAverage is ambiguous, both method calcAverage(double,int) in MyClass and method calcAverage(int,double) in MyClass match calcAverage(2, 3); ^ 1 error For primitive method arguments, if a call to an overloaded method is dubious, the code won’t compile. EXAM TIP Here’s an interesting question: Would an overloaded method with the following signature solve this specific problem? static double calcAverage(int marks1, int marks2) Yes, it will. Because the type of literal integer value is int, the compiler will be able to resolve the call calcAverage(2, 3) to calcAverage(int marks1, int marks2) and compile successfully. 1.2.2 When methods can’t be defined as overloaded methods The overloaded methods give you the flexibility of defining methods with the same name that can be passed a different set of arguments. But it doesn’t make sense to define overloaded methods with a difference in only their return types or access or nonaccess modifiers. RETURN TYPE Methods can’t be defined as overloaded methods if they only differ in their return types, as follows: class Result { double calcAverage(int marks1, int marks2) { return (marks1 + marks2)/2; } int calcAverage(int marks1, int marks2) { return (marks1 + marks2)/2; } } Return type of calcAverage() is double Return type of calcAverage() is int The methods defined in the preceding code aren’t correctly overloaded methods— they won’t compile. When the Java compiler differentiates methods, it doesn’t consider their return types. So you can’t define overloaded methods with the same parameter list and different return types. EXAM TIP Licensed to Mark Watson 35 Overloaded methods and constructors ACCESS MODIFIER Methods can’t be defined as overloaded methods if they only differ in their access modifiers, as follows: class Result { public double calcAverage(int marks1, int marks2) { return (marks1 + marks2)/2; } protected double calcAverage(int marks1, int marks2) { return (marks1 + marks2)/2; } } Access—public Access—protected NONACCESS MODIFIER Methods can’t be defined as overloaded methods if they only differ in their nonaccess modifiers, as follows: class Result { Nonaccess public synchronized double calcAverage(int marks1, int marks2) { modifier— return (marks1 + marks2)/2; synchronized } public final double calcAverage(int marks1, int marks2) { Nonaccess return (marks1 + marks2)/2; modifier— } final } Let’s revisit the rules for defining overloaded methods. Rules to remember for defining overloaded methods Here’s a quick list of rules to remember for the exam for defining and using overloaded methods: ■ ■ ■ ■ A class can overload its own methods and methods inherited from its base class. Overloaded methods must be defined with the same name. Overloaded methods must be defined with different parameter lists. Overloaded methods might define a different return type or access or nonaccess modifier, but they can’t be defined with only a change in their return types or access or nonaccess modifiers. In the next section, we’ll create overloaded versions of special methods, called constructors, which are used to create objects of a class. 1.2.3 Overloaded constructors While creating instances of a class, you might need to assign default values to some of its variables and assign explicit values to the rest. You can do so by overloading the Licensed to Mark Watson www.allitebooks.com 36 CHAPTER 1 Java class design constructors. Overloaded constructors follow the same rules as discussed in the previous section on overloaded methods: ■ ■ Overloaded constructors must be defined using a different argument list. Overloaded constructors can’t be defined by a mere change in their access modifiers. EXAM TIP Watch out for exam questions that use nonaccess modifiers with constructors. Using nonaccess modifiers with constructors is illegal—the code won’t compile. Here’s an example of class Employee, which defines four overloaded constructors: class Employee { String name; No-argument int age; constructor Employee() { name = "John"; age = 25; Constructor with one } String argument Employee(String newName) { name = newName; Constructor with age = 25; two arguments— } int and String Employee(int newAge, String newName) { name = newName; Constructor with age = newAge; two arguments— } String and int Employee(String newName, int newAge) { name = newName; age = newAge; } } b c d e In the previous code, the code at B defines a constructor that doesn’t accept any arguments, and the code at c defines another constructor that accepts a single argument. Note the constructors defined at d and e. Both of these accept two arguments, String and int. But the placement of these two arguments is different in d and e, which is acceptable and valid for overloaded constructors and methods. INVOKING AN OVERLOADED CONSTRUCTOR FROM ANOTHER CONSTRUCTOR It’s common to define multiple constructors in a class. Unlike overloaded methods, which can be invoked using the name of a method, overloaded constructors are invoked by using the keyword this—an implicit reference, accessible to an object, to refer to itself. For instance class Employee { String name; int age; Employee() { this(null, 0); } b No-argument constructor c Invokes constructor that accepts two arguments Licensed to Mark Watson 37 Overloaded methods and constructors Employee(String newName, int newAge) { name = newName; age = newAge; } d Constructor that accepts two arguments } The code at B defines a no-argument constructor. At c, this constructor calls the overloaded constructor by passing to it values null and 0. d defines an overloaded constructor that accepts two arguments. Because a constructor is defined using the name of its class, it’s a common mistake to try to invoke a constructor from another constructor using the class’s name: class Employee { String name; int age; Employee() { Employee(null, 0); } Employee(String newName, int newAge) { name = newName; age = newAge; } } Won’t compile—you can’t invoke a constructor within a class by using the class’s name. Also, when you invoke an overloaded constructor using the keyword this, it must be the first statement in your constructor: class Employee { String name; int age; Employee() { System.out.println("No-argument constructor"); this(null, 0); } Employee(String newName, int newAge) { name = newName; age = newAge; } } Won’t compile—call to overloaded constructor must be first statement in constructor. That’s not all: you can’t call a constructor from any other method in your class. None of the other methods of class Employee can invoke its constructor. Rules to remember for defining overloaded constructors Here’s a quick list of rules to remember for the exam for defining and using overloaded constructors: ■ ■ ■ Overloaded constructors must be defined using different argument lists. Overloaded constructors can’t be defined by just a change in the access modifiers. Overloaded constructors can be defined using different access modifiers. Licensed to Mark Watson 38 CHAPTER 1 Java class design (continued) ■ A constructor can call another overloaded constructor by using the keyword this. ■ A constructor can’t invoke a constructor by using its class’s name. ■ If present, the call to another constructor must be the first statement in a constructor. INSTANCE INITIALIZERS Apart from constructors, you can also define an instance initializer to initialize the instance variables of your class. An instance initializer is a code block defined within a class, using a pair of {}. You can define multiple instance initializers in your class. Each instance initializer is invoked when an instance is created, in the order they’re defined in a class. They’re invoked before a class constructor is invoked. Why do you think you need an instance initializer if you can initialize your instances using constructors? Multiple reasons exist: ■ ■ ■ For a big class, it makes sense to place the variable initialization just after its declaration. All the initializers are invoked, irrespective of the constructor that’s used to instantiate an object. Initializers can be used to initialize variables of anonymous classes that can’t define constructors. (You’ll work with anonymous classes in the next chapter.) Here’s a simple example: class Pencil { public Pencil() { System.out.println("Pencil:constructor"); } public Pencil(String a) { System.out.println("Pencil:constructor2"); } { System.out.println("Pencil:init1"); } { System.out.println("Pencil:init2"); } Added to both overloaded constructors public static void main(String[] args) { new Pencil(); new Pencil("aValue"); } } The output of the preceding code is Pencil:init1 Pencil:init2 Pencil:constructor Licensed to Mark Watson Overloaded methods and constructors 39 Pencil:init1 Pencil:init2 Pencil:constructor2 The next “Twist in the Tale” exercise hides an important concept within its code, which you can get to know only if you try to compile and execute the modified code. Twist in the Tale 1.2 Let’s modify the definition of class Employee used in the section on overloaded constructors as follows: class Employee { String name; int age; Employee() { this("Shreya", 10); } Employee (String newName, int newAge) { this(); name = newName; age = newAge; } void print(){ print(age); } void print(int age) { print(); } } What is the output of this modified code, and why? The instance initializer blocks are executed after an implicit or explicit call to the parent class’s constructor: class Instrument { Instrument() { System.out.println("Instrument:constructor"); } } class Pencil extends Instrument { public Pencil() { System.out.println("Pencil:constructor"); } { System.out.println("Pencil:instance initializer"); } public static void main(String[] args) { new Pencil(); } } Licensed to Mark Watson 40 CHAPTER 1 Java class design Alphabetical order Child constructor Child initialization block Execution order Got the execution order. 4 3 Parent constructor 2 Parent initialization block 1 Figure 1.17 The order of execution of constructors and instance initializers in parent and child classes The output of the preceding code is Instrument:constructor Pencil:instance initializer Pencil:constructor Figure 1.17 shows a fun way of remembering the order of execution of a parent class constructor, instance initializers, and a class constructor. Paul, our programmer, was having a very hard time remembering the order of execution of all these code blocks. He literally had to stand upside down to get the order right. If a parent or child class defines static initializer block(s), they execute before all parent and child class constructors and instance initializers—first for the parent and then for the child class. EXAM TIP Now that you’ve seen how to create the overloaded variants of methods and constructors, let’s dive deep into method overriding. These two concepts, overloading and overriding, seem to be confusing for a lot of programmers. Let’s get started by clearing the cobwebs. 1.3 Method overriding and virtual method invocation [1.2] Override methods [1.5] Use virtual method invocation Do you celebrate a festival or an event in exactly the same manner as celebrated by your parents? Or have your modified it? Perhaps you celebrate the same festivals and events, but in your own unique manner. In a similar manner, classes can inherit Licensed to Mark Watson Method overriding and virtual method invocation 41 behavior from other classes. But they can redefine the behavior that they inherit—this is also referred to as method overriding. Method overriding is an object-oriented programming (OOP) language feature that enables a derived class to define a specific implementation of an existing base class method to extend its own behavior. A derived class can override an instance method defined in a base class by defining an instance method with the same method signature/method name and number and types of method parameters. Overridden methods are also synonymous with polymorphic methods. The static methods of a base can’t be overridden, but they can be hidden by defining methods with the same signature in the derived class. A method that can be overridden by a derived class is called a virtual method. But beware: Java has always shied away from using the term virtual methods and you will not find a mention of this term in Java’s vocabulary. This term is used in other OO languages like C and C++. Virtual method invocation is the invocation of the correct overridden method, which is based on the type of the object referred to by an object reference and not by the object reference itself. It’s determined at runtime, not at compilation time. The exam will question you on the need for overridden methods; the correct syntax of overridden methods; the differences between overloaded, overridden, and hidden methods; common mistakes while overriding methods; and virtual method invocation. Let’s get started with the need for overridden methods. A base class method is referred to as the overridden method and the derived class method is referred to as the overriding method. NOTE 1.3.1 Need of overridden methods In the same way we inherit our parents’ behaviors but redefine some of the inherited behavior to suit our own needs, a derived class can inherit the behavior and properties of its base class but still be different in its own manner—by defining new variables and methods. A derived class can also choose to define a different course of action for its base class method by overriding it. Here’s an example of class Book, which defines a method issueBook() that accepts days as a method parameter: class Book { void issueBook(int days) { if (days > 0) System.out.println("Book issued"); else System.out.println("Cannot issue for 0 or less days"); } } Following is another class, CourseBook, which inherits class Book. This class needs to override method issueBook() because a CourseBook can’t be issued if it’s only for Licensed to Mark Watson 42 CHAPTER 1 Java class design reference. Also, a CourseBook can’t be issued for 14 or more days. Let’s see how this is accomplished by overriding method issueBook(): class CourseBook extends Book { boolean onlyForReference; CourseBook(boolean val) { onlyForReference = val; } @Override void issueBook(int days) { if (onlyForReference) System.out.println("Reference book"); else if (days < 14) super.issueBook(days); else System.out.println("days >= 14"); } } b Annotation— @Override c Overrides issueBook() in base class Book d Calls issueBook() defined in Book The code at B uses the annotation @Override, which notifies the compiler that this method overrides a base class method. Though optional, this annotation can come in very handy if you try to override a method incorrectly. The code at c defines method issueBook() with the same name and method parameters as defined in class Book. The code at d calls method issueBook() defined in class Book; however, it isn’t mandatory to do so. It depends on whether the derived class wants to execute the same code as defined by the base class. Whenever you intend to override methods in a derived class, use the annotation @Override. It will warn you if a method can’t be overridden or if you’re actually overloading a method rather than overriding it. NOTE The following example can be used to test the preceding code: class BookExample { public static void main(String[] args) { Book b = new CourseBook(true); b.issueBook(100); b = new CourseBook(false); b.issueBook(100); b = new Book(); b.issueBook(100); Prints “Book } issued” } Prints “Reference book” Prints “days >= 14” b now refers to a Book instance Figure 1.18 represents the compilation and execution process of class BookExample, as Step 1 and Step 2: ■ ■ Step 1: The compile time uses the reference type for the method check. Step 2: The runtime uses the instance type for the method invocation. Now let’s move on to how to correctly override a base class method in a derived class. Licensed to Mark Watson 43 Method overriding and virtual method invocation Step 1 Type of reference variable “b” is I must consult class Book to verify existence of method issueBook(). Book b = new CourseBook(true); b.issueBook(100); In Book. Java compiler Consult Compilation successful class Book { void issueBook(int days){ ..... } } BookExample.class – – – – Step 2 BookExample.class Type of object referred by “b” is CourseBook. I must consult CourseBook for description of method issueBook(). Book b = new CourseBook(true); b.issueBook(100); In 1 Java runtime 2 Consult 4 Result 3 Confusion Because method signatures are exactly the same, call issueBook() from CourseBook (type of object is CourseBook). class CourseBook extends Book { void issueBook(int days){ ..... } } Classes Book and CourseBook define method issueBook() with identical signatures. Book issueBook(int) CourseBook onlyForReference issueBook(int) Figure 1.18 To compile b.issueBook(), the compiler refers only to the definition of class Book. To execute b.issueBook(), the Java Runtime Environment (JRE) uses the actual method implementation of issueBook() from class CourseBook. Licensed to Mark Watson 44 CHAPTER 1 Java class design Method review() in Book Method review() in CourseBook Nonaccess modifiers Access modifiers synchronized protected List review (int id, throws List names) Exception final public ArrayList review (int id, throws List names) IOException Return type Same or different (conditions apply) Same or covariant Method name Parameter list Exact match Exception list None, same, or subclass Figure 1.19 Comparing parts of a method declaration for a base class method and overriding method 1.3.2 Correct syntax of overriding methods Let’s start with an example of overridden method review(), as follows: Method review() in base class Book class Book { synchronized protected List review(int id, List names) throws Exception { return null; } CourseBook } extends Book class CourseBook extends Book { @Override final public ArrayList review(int id, List names) throws IOException { return null; } Overridden method review() } in derived class CourseBook Figure 1.19 shows the components of a method declaration: access modifiers, nonaccess modifiers, return type, method name, parameter list, and a list of exceptions that can be thrown (method declaration isn’t the same as method signature). The figure also compares the review method defined in base class Book with overriding method review() defined in class CourseBook with respect to these identified parts. Table 1.2 compares the method components shown in figure 1.19. Table 1.2 Comparison of method components and their acceptable values for an overriding method Value in class Book Method component Access modifier protected Value in class CourseBook public Overriding method review() in class CourseBook Define same access or less restrictive access than method review() in the base class. Licensed to Mark Watson Method overriding and virtual method invocation 45 Table 1.2 Comparison of method components and their acceptable values for an overriding method Method component Value in class Book Value in class CourseBook Overriding method review() in class CourseBook Nonaccess modifier synchronized final Overriding method can use any nonaccess modifier for an overridden method. A nonabstract method can also be overridden to an abstract method. But a final method in the base class cannot be overridden. A static method cannot be overridden to be nonstatic. Return type List ArrayList Define the same or a subtype of the return type used in the base class method (covariant return types). Method name review review Exact match. Parameter list (int id, List names) (int id, List names) Exact match. Exceptions thrown throws Exception throws IOException Throw none, same, or a subclass of the exception thrown by the base class method. The rule listed in table 1.2 on exceptions in overriding methods only applies to checked exceptions. An overriding method can throw any unchecked exception (RuntimeException or Error) even if the overridden method doesn’t. The unchecked exceptions aren’t part of the method signature and aren’t checked by the compiler. EXAM TIP Chapter 6 includes a detailed explanation on overridden and overriding methods that throw exceptions. Let’s walk through a couple of invalid combinations that are important and very likely to be on the exam. Though a best practice, I’ve deliberately not preceded the definition of the overriding methods with the annotation @Override because you might not see it on the exam. NOTE ACCESS MODIFIERS A derived class can assign the same or more access but not a weaker access to the overriding method in the derived class: class Book { protected void review(int id, List names) {} } class CourseBook extends Book { void review(int id, List names) {} } Won’t compile; overriding methods in derived classes can’t use a weaker access. Licensed to Mark Watson 46 CHAPTER 1 Java class design NONACCESS MODIFIERS A derived class can’t override a base class method marked final: class Book { final void review(int id, List names) {} } class CourseBook extends Book { void review(int id, List names) {} } Won’t compile; final methods can’t be overridden. ARGUMENT LIST AND COVARIANT RETURN TYPES When the overriding method returns a subclass of the return type of the overridden method, it’s known as a covariant return type. To override a method, the parameter list of the methods in the base and derived classes must be exactly the same. It you try to use covariant types in the argument list, you’ll end up overloading the methods and not overriding them. For example class Book { void review(int id, List names) throws Exception { System.out.println("Base:review"); } } class CourseBook extends Book { void review(int id, ArrayList names) throws IOException { System.out.println("Derived:review"); } } b At Argument list— int and List Argument list—int and ArrayList B method review() in base class Book accepts an object of type List. Method review() in derived class CourseBook accepts a subtype ArrayList (ArrayList implements List). These methods aren’t overridden—they’re overloaded: class Verify { public static void main(String[] args)throws Exception { Book book = new CourseBook(); book.review(1, null); Calls review in } Book; prints } “Base:review” b Reference variable of type Book used to refer to object CourseBook. The code at B uses a reference variable of type Book to refer to an object of type CourseBook. The compilation process assigns execution of method review() from base class Book to the reference variable book. Because method review() in class CourseBook doesn’t override the review method in class Book, the JRE doesn’t have any confusion regarding whether to call method review() from class Book or from class CourseBook. It moves forward with calling review() from Book. EXAM TIP It’s the reference variable type that dictates which overloaded method will be chosen. This choice is made at compilation time. Licensed to Mark Watson 47 Method overriding and virtual method invocation EXCEPTIONS THROWN An overriding method must either declare to throw no exception, the same exception, or a subtype of the exception declared to be thrown by the base class method, or else it will fail to compile. This rule, however, doesn’t apply to error classes or runtime exceptions. For example Compiles; an overriding method can declare to throw any RuntimeException. class Book { void review() throws Exception {} void read() throws Exception {} void close() throws Exception {} void write() throws NullPointerException {} void skip() throws IOException {} void modify() {} } class CourseBook extends Book { void review() {} void read() throws IOException {} void close() throws Error {} void write() throws RuntimeException {} void skip() throws Exception {} void modify() throws IOException {} } Compiles; declares to throw no exception. Doesn’t compile; declares to throw IOException. Overriding method can’t declare to throw a checked exception if overridden method doesn’t. EXAM TIP Compiles; declares to throw IOException, a subclass of Exception. Compiles; an overriding method can declare to throw any Error. Doesn’t compile; declares to throw Exception, a superclass of IOException. Overriding method can’t declare to throw broader exceptions than declared to be thrown by overridden method. An overriding method can declare to throw any Runtime- Exception or Error, even if the overridden method doesn’t. To remember this preceding point, let’s compare exceptions with monsters. Figure 1.20 shows a fun way to remember the exceptions (monsters) that can be on the list of an Exception list overridden method (in base class) Exception list overriding method (in derived class) None Same Narrower Error RuntimeException None Error RuntimeException Figure 1.20 Comparing exceptions to monsters. When an overridden method declares to throw a checked exception (monster), the overriding method can declare to throw none, the same, or a narrower checked exception. An overriding method can declare to throw any Error or RuntimeException. Licensed to Mark Watson 48 CHAPTER 1 Java class design overriding method, when the overridden method doesn’t declare to throw a checked exception and when it declares to throw a checked exception. 1.3.3 Can you override all methods from the base class or invoke them virtually? The simple answer is no. You can override only the following methods from the base class: ■ ■ Methods accessible to a derived class Nonstatic base class methods METHODS ACCESSIBLE TO A BASE CLASS The accessibility of a method in a derived class depends on its access modifier. For example, a private method defined in a base class isn’t available to any of its derived classes. Also, a method with default access in a base class isn’t available to a derived class in another package. A class can’t override the methods that it can’t access. ONLY NONSTATIC METHODS CAN BE OVERRIDDEN If a derived class defines a static method with the same name and signature as the one defined in its base class, it hides its base class method and doesn’t override it. You can’t override static methods. For example class Book { static void printName() { System.out.println("Book"); } } class CourseBook extends Book { static void printName() { System.out.println("CourseBook"); } } Static method in base class Static method in derived class Method printName() in class CourseBook hides printName() in class Book. It doesn’t override it. Because the static methods are bound at compile time, the method printName() that’s called depends on the type of the reference variable: class BookExampleStaticMethod { public static void main(String[] args) { Book base = new Book(); base.printName(); Book derived = new CourseBook(); derived.printName(); } Prints “Book” Prints “Book” } Licensed to Mark Watson 49 Method overriding and virtual method invocation class Book{ public static void printName(){ .... } public int issueBook(int days){ .... } public int returnBook(int days){ .... } } Book + printName() + issueBook(int) + returnBook(int) Method hiding CourseBook class CourseBook extends Book{ public static void printName(){ .... Method } overloading public int issueBook(int days){ .... } public int issueBook(){ .... } public int returnBook(int a, int b){ .... } } + + + + printName() issueBook(int) issueBook() returnBook(int, int) Method overriding Method overloading Figure 1.21 Identifying method overriding, method overloading, and method hiding in a base and derived class 1.3.4 Identifying method overriding, overloading, and hiding It’s easy to get confused with method overriding, overloading, and hiding. Figure 1.21 identifies these methods in classes Book and CourseBook. On the left are the class definitions, and on the right their UML representations. When a class extends another class, it can overload, override, or hide its base class methods. A class can’t override or hide its own methods—it can only overload its own methods. EXAM TIP Let’s check out the correct code for defining a static or nonstatic method in a derived class that overrides or hides a static or nonstatic method in a base class using the next “Twist in the Tale” exercise. Twist in the Tale 1.3 Let’s modify the code of classes Book and CourseBook and define multiple combinations of static and nonstatic method print() in both these classes as follows: a class Book{ static void print(){} } Licensed to Mark Watson 50 CHAPTER 1 Java class design class CourseBook extends Book{ static void print(){} } b c d class Book{ static void print(){} } class CourseBook extends Book{ void print(){} } class Book{ void print(){} } class CourseBook extends Book{ static void print(){} } class Book{ void print(){} } class CourseBook extends Book{ void print(){} } Your task is to first tag them with one of the options and then compile them on your system to see if they’re correct. On the actual exam, you’ll need to verify (without a compiler) if a code snippet compiles or not: ■ ■ ■ 1.3.5 Overridden print() method Hidden print() method Compilation error Can you override base class constructors or invoke them virtually? The simple answer is no. Constructors aren’t inherited by a derived class. Because only inherited methods can be overridden, constructors cannot be overridden by a derived class. If you attempt an exam question that queries you on overriding a base class constructor, you know that it’s trying to trick you. EXAM TIP Constructors can’t be overridden because a base class constructor isn’t inherited by a derived class. Now that you know why and how to override methods in your own classes, let’s see in the next section why it’s important to override the methods of class java.lang.Object. Licensed to Mark Watson 51 Overriding methods of class Object 1.4 Overriding methods of class Object [1.6] Override methods from the Object class to improve the functionality of your class All the classes in java—classes from the Java API, user-defined classes, or classes from any other API—extend class java.lang.Object, either implicitly or explicitly. Because this section talks about overriding the methods from class Object, let’s take a look at its nonfinal and final methods in figure 1.22. You might write a Java class to be used in your small in-house project or a commercial project, or it could be a part of a library that may be released to be used by other programmers. As you have less control over who uses your class and how it’s used, the importance of correctly overriding methods from class Object rises. It’s important to override the nonfinal Object class methods so that these classes can be used efficiently by other users. Apart from being able to be used as desired, incorrect overriding of these methods can also result in increased debug time. Because the final methods can’t be overridden, I’ll discuss the nonfinal methods of class Object in this section. These methods—clone(), equals(), hashCode(), toString(), and finalize()—define a contract, a set of rules on how to override these methods, specified by the Java API documentation. 1.4.1 Overriding method toString() Method toString() is called when you try to print out the value of a reference variable or use a reference variable in a concatenation operator. The default implementation of method toString() returns the name of the class, followed by @ and the hash java.lang.Object Nonfinal methods clone() Final methods finalize() equals() toString() getClass() notifyAll() notify() wait() hashCode() Figure 1.22 Categorization of final and nonfinal methods of class java.lang.Object Licensed to Mark Watson 52 CHAPTER 1 Java class design code of the object it represents. Following is the code of method toString(), as defined in class Object in the Java API: toString() as defined in java.lang.Object public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } Following is an example of class Book, which doesn’t override method toString(). In this case, a request to print the reference variable of this class will call method toString() defined in class Object: class Book { String title; } class PrintBook { public static void main(String[] args) { Book b = new Book(); System.out.println(b); } } Prints a value similar to Book@45a877 Let’s override method toString() in class Book. The contract of method toString() specifies that it should return a concise but informative textual representation of the object that it represents. This is usually accomplished by using the value of the instance variables of an object: class Book { String title; toString() uses title @Override to represent Book public String toString() { return title; } } class Test { public static void main(String[] args) { Book b = new Book(); Prints book title, b.title = "Java Certification"; “Java Certification” System.out.println(b); } } If a class defines a lot of instance variables, method toString()might include only the important ones—that is, the ones that provide its concise description. In the following example, class Book defines multiple instance variables and uses a few of them in method toString(): class Book { String title; String isbn; String[] author; java.util.Date publishDate; Instance variables to store a Book’s state Licensed to Mark Watson 53 Overriding methods of class Object toString uses title, isbn, and the first element of array author to describe a Book. double price; int version; String publisher; boolean eBookReady; @Override public String toString() { return title + ", ISBN:"+isbn + } Instance variables to store a Book’s state ", Lead Author:"+author[0]; } class Test { public static void main(String[] args) { Book b = new Book(); b.title = "Java Smart Apps"; b.author = new String[]{"Paul", "Larry"}; b.isbn = "9810-9643-987"; System.out.println(b); } } Prints “Java Smart Apps, ISBN:9810-9643987, Lead Author:Paul” You have overridden method toString() inappropriately if it returns any text that’s specific to a particular class, for example, the name of a class or a value of a static variable: class Book { String title; static int bookCopies = 1000; @Override public String toString() { Overridden return title + ", Copies:" + bookCopies; toString() uses static } variable of Book. } class CourseBook extends Book { static int bookCopies = 99999; Static variable } bookCopies also class BookOverrideToString { defined in CourseBook public static void main(String[] args) { CourseBook b = new CourseBook(); b.title = "Java Smart Apps"; System.out.println(b); Prints “Java Smart } Apps, Copies:1000” } b c d In this code, B shows inappropriate overriding of method toString() because it uses a static variable. The code at c defines a static variable bookCopies in class CourseBook. Because static members are bound at compile time, method toString() will refer to the variable bookCopies defined in class Book, even if the object it refers to is of the type CourseBook. d prints the value of the static variable defined in class Book. Overriding methods of class Object is an important concept. Let it sink in. The next “Twist in the Tale” exercise will ensure that you get the hang of correct overriding of method toString(), before moving on to the next section. Licensed to Mark Watson 54 CHAPTER 1 Java class design Twist in the Tale 1.4 Which of the following classes—Book1, Book2, Book3, or Book4—shows an appropriate overridden method toString()? class Book1 { String title; int copies = 1000; public String toString() { return "Class Book, Title: " + title; } } class Book2 { String title; int copies = 1000; public String toString() { return ""+copies * 11; } } class Book3 { String title; int copies = 1000; public String toString() { return title; } } class Book4 { String title; int copies = 1000; public String toString() { return getClass().getName() + ":" + title; } } 1.4.2 Overriding method equals() Method equals() is used to determine whether two objects of a class should be considered equal or not. Figure 1.23 shows a conversation between two objects, wondering whether they’re equal or not. Are we equal? equals() knows it better! Figure 1.23 Applying a twist on Shakespeare’s quote: “Equal or not equal, that is the question.” Method equals() returns a boolean value that determines whether two objects should be considered equal or not. Licensed to Mark Watson Overriding methods of class Object 55 The default implementation of method equals() in class Object compares the object references and returns true if both reference variables refer to the same object, or false otherwise. In essence, it only returns true if an object is compared to itself. Following is the default implementation of method equals() in class java.lang.Object: public boolean equals(Object obj) { return (this == obj); } The exam will question you on the following points: ■ ■ ■ The need to override method equals() Overriding method equals() correctly Overriding method equals() incorrectly THE NEED TO OVERRIDE METHOD EQUALS() You need to override method equals() for objects that you wish to equate logically, which normally depends on the state of an object (that is, the value of its instance variables). The goal of overriding method equals() is to check for equality of the objects, not to check for the same variable references. For two objects of the same class, say, object1 and object2, equals() checks whether object1 is logically equal to object2, but object1 isn’t necessarily pointing to the exact same object as object2. For example, class String overrides method equals() to check whether two String objects define the exact same sequence of characters: String name1 = "Harry"; String name2 = new String ("Harry"); System.out.println(name1.equals(name2)); Prints “true” In the preceding code, name1 and name2 refer to separate String objects but define the exact same sequence of characters—"Harry". So name1.equals(name2) returns true. AN EXAMPLE You might need to find out whether the same undergraduate course is or is not offered by multiple universities. In an application, you can represent a university using a class, say, University, and each course being offered using a class, say, Course. Assuming that each university offers a list of courses, you can override method equals() in class Course to determine if two Course objects can be considered equal, as follows: class Course { String title; int duration; public boolean equals(Object o) { if (o != null && o instanceof Course) { Course c = (Course)o; return (title.equals(c.title) && duration==c.duration); } else return false; } } Licensed to Mark Watson 56 CHAPTER 1 Java class design RULES FOR OVERRIDING METHOD EQUALS() Method equals() defines an elaborate contract (set of rules), as follows (straight from the Java API documentation): 1 2 3 4 5 It’s reflexive—For any non-null reference value x, x.equals(x) should return true. This rule states that an object should be equal to itself, which is reasonable. It’s symmetric—For any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true. This rule states that two objects should be comparable to each other in the same way. It’s transitive—For any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true. This rule states that while comparing objects, you shouldn’t selectively compare the values based on the type of an object. It’s consistent—For any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified. This rule states that method equals() should rely on the value of instance variables that can be accessed from the memory and shouldn’t try to rely on values like the IP address of a system, which may be assigned a separate value upon reconnection to a network. For any non-null reference value x, x.equals(null) should return false. This rule states that a non-null object can never be equal to null. Quite a lot of rules to remember! Let’s use an interesting way to remember all these rules, by comparing equals() to love. So when you see “x.equals(x),” read it as “x.loves(x).” Read “if x.equals(y) returns true, y.equals(x) must return true” as “if x loves y, y loves x.” All these rules are shown in figure 1.24. They’ll make more sense when you cover them using these examples. CORRECT AND INCORRECT OVERRIDING OF METHOD EQUALS() To override method toString() correctly, follow the method overriding rules defined in section 1.3. Note that the type of parameter passed to equals() is Object. Watch out for exam questions that seem to override equals(), passing it to a parameter type of the class in which it’s defined. In the following example, class Course doesn’t override method equals(), it overloads it: class Course { String title; Course(String title) { this.title = title; } public boolean equals(Course o) { return title.equals(o.title); } public static void main(String args[]) { Object c1 = new Course("eJava"); Object c2 = new Course("eJava"); System.out.println(c1.equals(c2)); } } Course doesn’t override toString(), it overloads it. Prints “false” Licensed to Mark Watson 57 Overriding methods of class Object I love myself! x.equals(x) is true x If If I love you... I love you! if x.equals(y)==true then y.equals(x) should be true x y IfIf I love y... If If I love z ... x loves me! if x.equals(y)==true and if y.equals(z)==true then x.equals(z) should be true x y z If we love each other now... we’ll always love each other. if x.equals(y)==true then it is always true x y I cannot love null! if (x != null) then x.equals(null) is false x Figure 1.24 with love. A fun way to remember all the rules of the equals() contract by comparing equals() Licensed to Mark Watson 58 CHAPTER 1 Java class design Use Object as the parameter type to equals(). Using any other type will overload equals(). EXAM TIP APPROPRIATE AND INAPPROPRIATE OVERRIDING OF METHOD EQUALS() If you don’t follow the contract of method equals() while overriding it in your classes, you’ll be overriding it inappropriately. An inappropriately overridden method equals() doesn’t mean compilation failure. An inappropriately overridden method equals() doesn’t mean compilation failure. EXAM TIP In the following code, class Course doesn’t comply with the symmetric and reflexive rules while overriding method equals(). Class University shows how these rules aren’t adhered to: class Course { String title; Course(String title) { this.title = title; } public boolean equals(Object o) { return (title.equals(o)); } } class University { public static void main(String[] args) { Course c1 = new Course("level1"); String s1 = "level1"; System.out.println(c1.equals(s1)); System.out.println(s1.equals(c1)); Compares title of course with object passed to equals b System.out.println(c1.equals(c1)); } } c Shows violation of symmetric rule— c1.equals(s1) prints “true” but s1.equals(c1) prints “false” Shows violation of reflexive rule— c1.equals(c1) prints “false” The code at B prints true for c1.equals(s1) and false for s1.equals(c1), which is a clear violation of equals()’s symmetric contract, which states that for any non-null reference values x and y, x.equals(y) should print true if and only if y.equals(x) returns true. The Course object will not evaluate to true in String’s method equals() because equals() in String first verifies if the object being compared to it is a String object before checking to see if their character sequence is the same. At c, c1.equals(c1) prints false, violating the reflexive rule that states that an object should be equal to itself. Let’s work with another example, where class JavaCourse violates the transitive rule while overriding method equals(). Class JavaCourse extends class Course and defines method equals(), which compares its object to both an object of Course and JavaCourse. Method equals() compares the common attributes, if the object being compared is that of the base class Course. It also compares all the attributes, if the object being compared is of class JavaCourse: Licensed to Mark Watson Overriding methods of class Object 59 class Course { String title; Course(String title) { this.title = title; } public boolean equals(Object o) { if (o instanceof Course) { Course c = (Course)o; return (title.equals(c.title)); } else return false; } } class JavaCourse extends Course { int duration = 0; JavaCourse(String title, int duration) { super(title); this.duration = duration; } public boolean equals(Object o) { if (o instanceof JavaCourse) { return (super.equals(o) && ((JavaCourse)o).duration == duration); } else if(o instanceof Course) { return (super.equals(o)); } else return false; } } In the following code for class University2, c1 is equal to c2 and c2 is equal to c3 because these comparisons only check the course title. But c1 isn’t equal to c3 because the course durations aren’t the same. Therefore, the overridden method equals() in class JavaCourse fails the transitive rule: class University2 public static Course c1 Course c2 Course c3 { void main(String[] args) { = new JavaCourse("level1", 2); = new Course("level1"); = new JavaCourse("level1", 12); System.out.println(c1.equals(c2)); System.out.println(c2.equals(c3)); System.out.println(c1.equals(c3)); } } Inappropriate overriding of method equals() can result in bizarre behavior. Use of equals() by collection classes is explained in detail in chapter 4. Licensed to Mark Watson 60 CHAPTER 1 Java class design The programmers claim you’re in a relationship and often call each other. Interviewer Figure 1.25 1.4.3 No!! We don’t even have each other’s phone number. equals() hashCode() Methods hashCode() and equals() don’t call each other. Overriding method hashCode() First, method hashCode() isn’t called by method equals() or vice versa. The contract of methods equals() and hashCode() mentions that both these methods should be overridden if one of them is overridden. This makes a lot of programmers believe that perhaps these methods are called by each other, which isn’t the case. Figure 1.25 shows a fun way to remember that methods equals() and hashCode() deny being in a relationship and calling each other. THE NEED TO OVERRIDE METHOD HASHCODE() Method hashCode() returns a hash-code value for an object, which is used to effi- ciently store and retrieve values in collection classes that use hashing algorithms, such as HashMap. Hashing algorithms identify the buckets in which they would store the objects and from which they would retrieve them. A well-written method hashCode() ensures that objects are evenly distributed in these buckets. Objects with the same hash-code values are stored in the same bucket. To retrieve an object, its bucket is identified using its hash-code value. If the bucket contains multiple objects, method equals() is used to find the target object. To understand how this works, let’s create a class called MyNumber, which contains a primitive long as its field. It returns a sum of all the individual digits of its field as its method hashCode(), as follows: class MyNumber { long number; MyNumber(long number) {this.number = number;} public int hashCode() { int sum = 0; long num = number; do { sum += num % 10; num /= 10; } while( num != 0 ); return sum; } } Licensed to Mark Watson Overriding methods of class Object 61 Let’s assume you add the following keys and values in a HashMap: Map map = new HashMap<>(); value 3 = new MyNumber(1200); = new MyNumber(2500); Hash-code = new MyNumber(57123); value 7 "John"); "Mary"); Hash-code "Sam"); value 18 With the preceding keys, each bucket contains only one entry. When you request the HashMap to retrieve a value, it would find the corresponding bucket using the key’s hash-code value and then it retrieves the value. Now let’s add another key-value pair: MyNumber num4 = new MyNumber(57123); map.put(num4, "Kim"); Hash-code value 18 Now the bucket with the hash-code value 18 has two String values. In this case, HashMap would use the hashCode() value to identify the bucket and then call method equals() to find the correct object. This explains why distinct hash-code values for distinct values are preferred. Chapter 4 explains in detail how the hashing algorithms in collection classes use methods hashCode() and equals(). NOTE OVERRIDING METHOD HASHCODE() CORRECTLY Here’s the signature of method hashCode() as defined in class Object: public native int hashCode(); To correctly override method hashCode(), you must follow the rules already discussed in section 1.3. Watch out for exam questions that use the incorrect case for hashCode()—the correct name uses uppercase C. Figure 1.26 shows a fun way to remember this simple, but important, exam point. I take all coding seriously! That’s why Code starts with capital C in hashCode(). hashCode() Figure 1.26 The correct case of hashCode() includes a capital C. Licensed to Mark Watson 62 CHAPTER 1 Java class design If we are in love… we must must reside at the same address. if x.equals(y)==true x.hashCode()== y.hashCode() must be true Before marriage y x If we are not not in love… we might might or might not reside at the same address. if x.equals(y)==false x.hashCode() and y.hashCode() can be same or different x Post breakup.... y Figure 1.27 Comparing equals() with being in love and hashCode() with an address. If two objects are equal, they must return the same hashCode(). But if two objects return the same hashCode(), they might not be equal. To override method hashCode() correctly, you must also abide by its contract, as mentioned in the Java documentation. For the exam, the following rules are important: 1 2 If two objects are equal according to method equals(Object), then calling method hashCode() on each of the two objects must produce the same integer result. It’s not required that if two objects are unequal according to method equals (java.lang.Object), that calling method hashCode() on each of the two objects must produce distinct integer results. Let’s use a fun analogy to remember these rules, as shown in figure 1.27. Let’s compare method equals() to being in love and method hashCode() to a physical address. When two objects are in love with each other, they must reside at the same address (this is what they think before they marry). Later, if they fall out of love, they might or might not continue to reside at the same address. Figure 1.27 will make more sense as you work with the code examples in this section. Let’s revisit the previous example, including equals() and verifying the rules: class MyNumber { long number; MyNumber(long number) {this.number = number;} Licensed to Mark Watson Overriding methods of class Object public int hashCode() { int sum = 0; long num = number; do { sum += num % 10; num /= 10; } while( num != 0 ); return sum; } public boolean equals(Object o) { if (o != null && o instanceof MyNumber) return (number == ((MyNumber)o).number); else return false; } public static void main(String args[]) { MyNumber n1 = new MyNumber(9); MyNumber n2 = new MyNumber(18); MyNumber n3 = new MyNumber(18); System.out.println (n1.equals(n2)+":"+n1.hashCode()+":"+n2.hashCode()); System.out.println (n2.equals(n3)+":"+n2.hashCode()+":"+n3.hashCode()); } } 63 Prints “false:9:9” Prints “true:9:9” The preceding code abides by both the rules of the hashCode() contract, when n2.equals(n3) returns true, n2.hashCode() and n3.hashCode() return the same value. But when n1.equals(n2) returns false, n1.hashCode() and n2.hashCode() might not return distinct values. Let’s modify the preceding code, so that hashCode() returns distinct values when equals() returns false: class MyNumber { long number; MyNumber(long number) {this.number = number;} public int hashCode() { return (int)number; } public boolean equals(Object o) { if (o != null && o instanceof MyNumber) return (number == ((MyNumber)o).number); else return false; } public static void main(String args[]) { MyNumber n1 = new MyNumber(9); MyNumber n2 = new MyNumber(18); MyNumber n3 = new MyNumber(18); System.out.println (n1.equals(n2)+":"+n1.hashCode()+":"+n2.hashCode()); System.out.println (n2.equals(n3)+":"+n2.hashCode()+":"+n3.hashCode()); } } Licensed to Mark Watson Prints “false:9:18” Prints “true:18:18” 64 CHAPTER 1 Java class design NOTE Using a system-dependent value (like a memory address) is allowed in hashCode(). But objects of such classes can’t be used as keys in distributed systems because equal objects (across systems) will return different hash-code values. OVERRIDING METHOD HASHCODE() INAPPROPRIATELY Inappropriate overriding isn’t the same as incorrect overriding—the former won’t fail compilation but can have issues with object retrieval. On the exam, watch out for questions that will show code for hashCode(), equals(), or both, and query what happens when the class instances are used as keys in collection classes, like HashMap. In this section, you’ll work with examples that override hashCode() correctly—syntactically, but not appropriately. In the previous section you learned why it’s important for method hashCode() that two objects return the same value, if they’re equal as per method equals(). Failing this condition, an object value will never be able to be retrieved from a HashMap. Let’s see what happens when class MyNumber doesn’t return the same hashCode() values for its equal objects: class MyNumber { int primary, secondary; MyNumber(int primary, int secondary) { this.primary = primary; Doesn’t print this.secondary = secondary; same hashCode() } value for equal public int hashCode() { objects return secondary; } public boolean equals(Object o) { if (o != null && o instanceof MyNumber) return (primary == ((MyNumber)o).primary); else return false; } public static void main(String args[]) { Prints “true”— Map map = new HashMap<>(); objects num1 MyNumber num1 = new MyNumber(2500, 100); and num2 are MyNumber num2 = new MyNumber(2500, 200); considered equal. System.out.println(num1.equals(num2)); map.put(num1, "Shreya"); System.out.println(map.get(num2)); Prints } “null” } b c d In the preceding code, even though the code at c prints true, confirming that objects num1 and num2 are considered equal by equals(), the code at d prints null. The reason for this? The hashCode() in MyNumber doesn’t return the same values for its equal objects. In method hashCode(), the code at B uses secondary to calculate its value, which isn’t used by equals(). Licensed to Mark Watson 65 Overriding methods of class Object Another rule of method hashCode() is that when it’s invoked on the same object more than once during the execution of a Java application, hashCode() must consistently return the same integer, provided no information used in the equals() comparisons on the object is modified. This integer doesn’t need to remain consistent from one execution of an application to another execution of the same application. Let’s see what happens when hashCode() doesn’t return the same integer value when it’s invoked on the same instance during the execution of a Java application: class MyNumber { int number; MyNumber(int number) {this.number = number;} public int hashCode() { return ((int)(Math.random() * 100)); } public boolean equals(Object o) { if (o != null && o instanceof MyNumber) return (number == ((MyNumber)o).number); else return false; } public static void main(String args[]) { Map map = new HashMap<>(); MyNumber num1 = new MyNumber(2500); map.put(num1, "Shreya"); System.out.println(map.get(num1)); } } Prints random hashcode values on each invocation Prints “null” (most probably) In the preceding code, when you add key-value num1, "Shreya" to HashMap, you most likely won’t be able to retrieve Shreya using the same key, num1. This is because each call to num1.hashCode() might return a different value (the chances of returning the same hashCode() values aren’t ruled out, but are very low). INEFFICIENT OVERRIDING OF HASHCODE() In real projects, always strive for generating distinct values in hashCode(). Distinct hashCode() values and faster object access are directly related in collection objects that use hashing functions to retrieve and store values. Here’s an example of inefficient overriding of method hashCode(): class MyNumber { long number; MyNumber(long number) {this.number = number;} public int hashCode() { return 1654; } } In the preceding code, method hashCode() returns the same hash-code value for all the objects of MyNumber. This essentially stores all the values in the same bucket, if Licensed to Mark Watson 66 CHAPTER 1 Java class design objects of the above class are used as keys in class HashMap (or in similar classes that use hashing), and reduces it to a linked list, drastically reducing its efficiency. Read the questions on method hashCode() carefully. You might be questioned on incorrect, inappropriate, or inefficient overriding of hashCode(). EXAM TIP EFFECTS OF USING MUTABLE OBJECTS AS KEYS Java recommends using immutable objects as keys for collection classes that use the hashing algorithm. What if you don’t? The exam might query you on this important question. Revisiting the example used in the previous section, what happens if the value of the field number is changed during the course of the application? In this case, you’ll never be able to retrieve the corresponding value in the HashMap, because the HashMap will not be able to look for the right bucket: class MyNumber { int number; MyNumber(int number) {this.number = number;} public int hashCode() { return number; } public boolean equals(Object o) { if (o != null && o instanceof MyNumber) return (number == ((MyNumber)o).number); else return false; } public static void main(String args[]) { Map map = new HashMap<>(); MyNumber num1 = new MyNumber(2500); map.put(num1, "Shreya"); num1.number = 100; System.out.println(map.get(num1)); } } Add value Shreya to HashMap using key num1. Modify field number of key num1, which is used by equals() and hashCode(). Prints “null”—can’t locate object with modified key. In the preceding code, the field used to determine the hash code of an object is modified in main(). With the modified key, HashMap won’t be able to retrieve its corresponding object. In the next section, you’ll cover when, why, and how you can cast an instance to another type and use the instanceof operator. 1.5 Casting and the instanceof operator [1.4] Use the instanceof operator and casting Imagine that you enroll yourself for flying classes, where you expect to be trained by an experienced pilot. Even though your trainer might also be a swimming champion, Licensed to Mark Watson Casting and the instanceof operator 67 you need not know about it. You need not care about the characteristics and behavior that’s not related to flying. Now think of a situation when you do care about the swimming skills of your instructor. Imagine that when you’re attending the flying classes, your friend enquires whether your flying instructor also conducts swimming classes and, if yes, whether she would be willing to assist your friend. In this case, a need arises to enquire about the swimming skills (additional existing skills) of your flying instructor. Similarly, in Java, you can refer to an object of a derived class using a reference variable of its base class or implemented interface. But you might need to access the members of the derived class, which aren’t defined in its base class or the implemented interface. Here’s when casting can help. Casting shows how an object of a type can be used as an object of another type, either implicitly or explicitly. The instanceof operator is used to logically test whether an object is a valid type of a class or an interface. 1.5.1 Implicit and explicit casting Let’s start with the definitions of the interface Printable and classes ShoppingItem and Book to show implicit and explicit casting. Class Book extends class ShoppingItem and implements the interface Printable as follows: public interface Printable { void print(); } public class ShoppingItem { public void description() { System.out.println("Shopping Item"); } } public class Book extends ShoppingItem implements Printable { public void description() { System.out.println("Book"); } public void print() { System.out.println("Printing book"); } } Figure 1.28 shows the inheritance relationship between these classes. Printable ShoppingItem Implements < > Book Figure 1.28 Relationship between classes ShoppingItem and Book and the interface Printable Licensed to Mark Watson 68 CHAPTER 1 Java class design Now let’s create variables of type Printable and ShoppingItem and assign to them objects of the type Book: class Shopping { public static void main(String args[]) { Book book = new Book(); Printable printable = book; printable.print(); ShoppingItem shoppingItem = book; shoppingItem.description(); } b c Implicit casting Acceptable } The code at B shows how an object of type book is implicitly referred to, or casted to, type Printable. The code at c shows how an object of type book is implicitly referred to, or casted to, type ShoppingItem. Objects of subclasses can be implicitly casted to their base classes or the interfaces that they implement. As shown in the preceding code block for the class Book, you can see that Book defines a method description(). Let’s try to access it using the printable variable: class Shopping { public static void main(String args[]) { Printable printable = new Book(); printable.description(); } } b Won’t compile—can’t access method description() in Printable. The code at B fails to compile with the following message: Shopping.java:4: error: cannot find symbol printable.description(); ^ symbol: method description() location: variable printable of type Printable 1 error Because the type of the reference variable printable is Printable, the compiler refers to the definition of the interface Printable when you call method description() on printable. Figure 1.29 shows what happens behind the scenes. But you know that the actual object is of type Book. Is there a way to treat the reference variable printable as a Book? Yes, there is! You need to inform the compiler you know what you’re doing by using an explicit cast, as follows (see also figure 1.30): class Shopping { public static void main(String args[]) { Printable printable = new Book(); ((Book)printable).description(); } } Licensed to Mark Watson Casting and the instanceof operator I just consulted interface Printable.It doesn’t define method description(). printable.description(); In interface Printable{ public void print(); } Java compiler Consult Compilation error Out Figure 1.29 The Java compiler doesn’t compile code if you try to access description(), defined in class Book, by using a variable of the interface Printable. Okay! So now I must consult class Book to determine the existence of method description(). ((Book)printable).description(); In Java compiler Consult Out class Book extends ShoppingItem implements Printable{ public void description(){ .... } .... .... .... } Compilation successful Figure 1.30 Explicit casting can be used to access description() defined in class Book by using a variable of the interface Printable. Licensed to Mark Watson 69 70 CHAPTER 1 Java class design interface Printable { void print(); } class ShoppingItem { public void description() { System.out.println("Shopping Item"); } } class Chair extends ShoppingItem { public void description() { System.out.println("Chair"); } } class Book extends ShoppingItem implements Printable { public void description() { System.out.println("Book"); } public void print() { System.out.println("Printing book"); } } Figure 1.31 Printable ShoppingItem < > < > Chair Implements Book Set of classes and interfaces, with their UML representation In the preceding code, (Book) is placed just before the name of the variable, printable, to cast it to Book. Note how a pair of parentheses surrounds (Book)printable. Casting in this line of code is another method of telling the compiler that you know that the actual object being referred to is Book, even though you’re using a reference variable of type Printable. 1.5.2 Combinations of casting To work with a combination of casting, let’s work with a set of classes and interfaces, as shown in figure 1.31. ASSIGNMENTS WITH IMPLICIT CASTING Implicit upcasting is allowed. You can assign a reference variable of a derived class to a reference variable of its own type, its base classes, and the interfaces that it implements as follows: public class UpcastWithImplicitCasting { public static void main(String[] arguments) { Book book = new Book(); Chair chair = book; ShoppingItem shoppingItem = book; Printable printable = book; Object object = book; Okay—a book is Printable. Chair chair2 = new Chair(); Printable printable2 = chair; } } Won’t compile—both Book and Chair extend ShoppingItem, but don’t belong to a single line of inheritance. Okay—a book is a ShoppingItem. Okay—a book is an Object. Won’t compile—Chair doesn’t implement Printable. Licensed to Mark Watson 71 Casting and the instanceof operator Implicit downcasting isn’t allowed. You can’t assign reference variables of a base class to reference variables of its derived classes or to the interfaces that it doesn’t implement. For example Won’t compile—a ShoppingItem isn’t necessarily a chair. Won’t compile—a ShoppingItem isn’t necessarily a book. public class DowncastWithImplicitCasting { public static void main(String[] arguments) { ShoppingItem shoppingItem3 = new ShoppingItem(); Won’t compile— a ShoppingItem isn’t Printable. Book book3 = shoppingItem3; Chair chair3 = shoppingItem3; Printable printable3 = shoppingItem3; Object object3 = shoppingItem3; } } EXAM TIP Okay—a chair is an Object. In the absence of explicit casting, you’ll never get ClassCast- Exception—a RuntimeException. ASSIGNMENT WITH EXPLICIT CASTING Both implicit and explicit upcasting are allowed. So, for the exam, let’s focus on explicit downcasting. Java recommends programming to an interface, which implies using reference variables of a base class or implementing interfaces to refer to the actual objects. But you might need to cast an object referred by a base class to its specific type. You can downcast an object to a type that falls in its inheritance tree using explicit casting. For a nonfinal class, you can explicitly cast its object to any interface type, even if the class doesn’t implement the interface. Let’s see what happens when you accept a method parameter of type ShoppingItem and try to cast it explicitly to other types: public class DowncastWithExplicitCasting { static void downCast(ShoppingItem item) { Book book = (Book)item; Chair chair = (Chair)item; Printable printable = (Printable)item; } public static void main(String args[]) { ShoppingItem item = new ShoppingItem(); downCast(item); } } b Compiles with casting—will throw ClassCastException; can’t downcast instance of parent object to subclass type. c Compiles with casting—will throw ClassCastException; ShoppingItem doesn’t implement Printable. The code at B and c compiles with an explicit cast. But its individual lines will fail at runtime. At runtime, Java can determine the exact type of the object being casted. It throws a ClassCastException if you’re trying to cast types that aren’t allowed. NOTE For the exam, you need to be very clear whether an explicit cast will result in a compilation error or a runtime exception (ClassCastException). Licensed to Mark Watson 72 CHAPTER 1 Java class design Does the preceding code make you wonder why an explicit cast from a ShoppingItem instance to Printable is permitted, even though ShoppingItem doesn’t implement Printable? It’s to allow subclasses of ShoppingItem to implement Printable and use the reference variable of type Printable to refer to its instances. So what happens if you try to cast a final class’s instance to an interface it doesn’t implement? The code won’t compile: interface Printable {} final class Engineer {} class Factory { public static void main(String[] args) { Engineer engineer = new Engineer(); Printable printable = (Printable)engineer; } } Won’t compile—can’t cast final class Engineer’s instance to Printable. Class String is defined as a final class. Watch out for questions that explicitly cast String objects to interfaces they don’t implement. They won’t compile. EXAM TIP What about casting null to a type? You can explicitly cast null to any type without a compilation error or runtime exception (ClassCastException): static void castNull() { Book book = (Book)null; Chair chair = (Chair)null; Printable printable = (Printable)null; } You can explicitly cast null to any type. It won’t generate a compilation error or throw a ClassCastException. EXAM TIP ACCESS OF MEMBERS WITH EXPLICIT CASTING You can access methods and variables of explicitly casted variables in single or multiple lines of code: public class AccesMembersWithExplicitCasting { static void accessMember(ShoppingItem item) { Book book = (Book)item; book.description(); ((Book)item).description(); } } c b Cast a reference variable and access its method in multiple steps. Cast objects and call their members in a single step. Here the code at B casts a reference item to Book in one line and then accesses its method description(). At c, note how the object referred by item is castedenclosed within () to call its member method description(). The inclusion in () is due to the fact that the dot operator has precedence over the casting parentheses. Licensed to Mark Watson 73 Casting and the instanceof operator If you cast an instance to a class outside its inheritance tree, you’ll get a compiler error. If you cast an instance to a class within its inheritance tree, but the types don’t match at runtime, the code will throw a ClassCastException. EXAM TIP Points to remember for casting ■ ■ ■ ■ ■ ■ An instance can be implicitly casted to its superclasses or interfaces that it implements. An instance of a nonfinal class can be explicitly casted to any interface at compile time. Classes in the same inheritance tree can be casted to each other using explicit casting at compile time. Objects of classes that don’t form part of the same inheritance tree cannot be casted. Casting to an interface is successful at runtime if the class implements the interface. Casting to a derived class type is successful at runtime if the casted object is actually a type of the derived class to which it’s casted. In the previous examples, you learned how mismatching of objects and explicit casting can throw a ClassCastException. In the next section, you’ll see how you can prevent this by using the instanceof operator to safely cast objects to a type. 1.5.3 Using the instanceof operator The instanceof operator is used to logically test whether an object is a valid type of a class or an interface. You should proceed with explicit casting only if this operator returns true, or you risk running into a ClassCastException at runtime. For example, consider equals(), which defines a method parameter of type Object. When you override equals() to determine the equality of objects of your class, you might need to query the state of the accepted argument before you move forward with an explicit cast: class Course { String title; Course(String t) {title = t;} public boolean equals(Object obj) { if (obj instanceof Course) { Course c = (Course)obj; return (title.equals(c.title)); } else return false; } } b Use instanceof to verify if obj is an instance of Course. c Explicitly cast obj to Course. The code at B ensures that the type of the accepted method parameter—that is, obj—is Course, before it moves forward with the explicit casting of obj to Course c. Licensed to Mark Watson 74 CHAPTER 1 Java class design In the absence of this check, the code at c would execute for all non-null method parameters, which can result in a ClassCastException if the object passed to equals() isn’t of type Course. The operator instanceof returns false if the reference variable being compared to is null. EXAM TIP In the previous example, the type of method parameter to equals() is Object, which is the parent class of all classes. But if the instanceof operator uses inconvertible types, the code won’t compile. In the following example, the instanceof operator uses a reference variable of type Course to test whether the object that it refers to can be an instance of class Student. Because Course and Student are unrelated, class Test won’t compile: class Course {} class Student {} public class TestInstanceof { public static void main(String[] args) { Course c = new Course(); Student s = new Student(); System.out.println(c instanceof Student); } } Won’t compile—can’t use instanceof to compare inconvertible types. The instanceof operator never throws a runtime exception; it returns either true or false. If the instanceof operator uses inconvertible types, the code won’t compile. EXAM TIP The instanceof operator is preceded by a value (literal value or a variable name) and is followed by a class, interface, or enum name. It’s acceptable to use the literal value null with the instanceof operator: class Course { public static void main(String[] args) { System.out.println(null instanceof Course); } } Prints “false”—null can’t be an instance of any class. The literal value null isn’t an instance of any class. So instanceof will return false whenever the is null. EXAM TIP Using instanceof versus getClass in method equals() Using instanceof versus getClass is a common subject of debate about proper use and object orientation in general (including performance aspects, design patterns, and so on). Though important, this discussion is beyond the scope of this book. If you’re interested in further details, refer to Josh Bloch’s book Effective Java. Licensed to Mark Watson 75 Packages How would you help your fans remember that o is lowercase in instanceof ? I’m a Java keyword and all Java keywords are lowercase. Interviewer Figure 1.32 instanceof Remember that o in instanceof is lowercase. Note that o in instanceof is lowercase; take a look at figure 1.32 for a fun way of remembering this. Next we’ll move forward with defining the Java classes and interfaces in named packages. This is a common requirement in real Java applications. So let’s get started. 1.6 Packages [1.7] Use package and import statements In this section, you’ll learn what Java packages are and how to create them. You’ll use the import statement, which enables you to use simple names for classes and interfaces defined in separate packages. 1.6.1 The need for packages You can use packages to group together a related set of enums, classes, and interfaces. Packages also provide namespace management. You can create separate packages to define classes for separate projects, such as Android games and online healthcare systems. Further, you can create subpackages within these packages, such as separate subpackages for GUIs, database access, networking, and so on. In real-life projects, you’ll never work with a package-less class or interface. Almost all organizations that develop software have strict package-naming rules, which are often documented. NOTE If you don’t include an explicit package statement in a class or an interface, it’s part of a default package. Licensed to Mark Watson 76 1.6.2 CHAPTER 1 Java class design Defining classes in a package using the package statement You can define classes and interfaces in a package by using the package statement as the first statement in your class or interface (only comments can precede the package statement). Here’s an example: package certification; class ExamQuestion { //..code } The class in the previous code defines a class ExamQuestion in the certification package. You can define an interface, MultipleChoice, in a similar manner: package certification; interface MultipleChoice { //..code } Figure 1.33 shows the UML representation of the certification package, with class ExamQuestion and interface MultipleChoice. The name of the package in the previous examples is certification. You may use such names for small projects that contain only a few classes and interfaces, but it’s common for organizations to use subpackages to define all their classes. For example, if folks at Oracle define a class to store exam questions for a Java Associate exam, they might use the package name com.oracle.javacert.associate. For subpackages, the package statement includes the complete package name. Figure 1.34 shows its UML representation along with the corresponding class definition. certification ExamQuestion MultipleChoice Figure 1.33 A UML representation of the certification package, class ExamQuestion, and interface MultipleChoice NOTE A fully qualified name for a class or interface is formed by prefixing its name with its package name (separated by a period). The fully qualified name of the ExamQuestion class is certification.ExamQuestion in figure 1.33 and com.oracle.javacert.associate.ExamQuestion in figure 1.34. package com.oracle.javacert.associate; class ExamQuestion { // variables and methods } Figure 1.34 com.oracle.javacert.associate ExamQuestion A subpackage and its corresponding class definition Licensed to Mark Watson Packages 77 Rules to remember about packages Here are a few important rules about packages: ■ ■ ■ ■ ■ ■ Per Java naming conventions, package names should all be in lowercase. The package and subpackage names are separated using a dot (.). Package names follow the rules defined for valid identifiers in Java. For packaged classes and interfaces, the package statement is the first statement in a Java source file (a .java file). The exception is that comments can appear before or after a package statement. There can be a maximum of one package statement per Java source code file (.java file). All the classes and interfaces defined in a Java source code file will be defined in the same package. There’s no way to define them in different packages. DIRECTORY STRUCTURE AND PACKAGE HIERARCHY The hierarchy of the classes defined in packages should match the hierarchy of the directories in which these classes and interfaces are defined in the code. For example, class ExamQuestion in the certification package should be defined in a directory with the name certification. The name of the certification directory and its location are governed by the rules shown in figure 1.35. This can be any directory. This structure should match the package hierarchy, certification. Figure 1.35 Matching directory structure and package hierarchy For the package example shown in figure 1.35, note that there isn’t any constraint on the location of the base directory in which the directory structure is defined. Examine figure 1.36. This can be any directory. This structure should match the package hierarchy, com.oracle.javacert.associate. Figure 1.36 There’s no constraint on the location of the base directory to define directories corresponding to package hierarchy. Licensed to Mark Watson 78 CHAPTER 1 Java class design SETTING THE CLASS PATH FOR CLASSES IN PACKAGES To enable the JRE to find your classes, interfaces, and enums defined in packages, add the base directory that contains your Java code to the class path. For example, to enable the JRE to locate the certification.ExamQuestion class from the previous examples, add the directory C:\MyCode to the class path. To enable the JRE to locate class com.oracle.javacert.associate.ExamQuestion, add the directory C:\ProjectCode to the class path. You don’t need to bother setting the class path if you’re working with an integrated development environment (IDE). But I strongly encourage you to learn how to work with a simple text editor and how to set a class path. This can be particularly helpful with your projects at work. I’ve also witnessed many interviewers querying candidates on the need for class paths. 1.6.3 Using simple names with import statements The import statement enables you to use simple names instead of using fully qualified names for classes and interfaces defined in separate packages. Let’s work with an example, in which classes LivingRoom and Kitchen are defined in the package home and classes Cubicle and ConferenceHall are defined in the package office. Class Cubicle uses (is associated to) class LivingRoom in the package home, as shown in figure 1.37. home office LivingRoom Cubicle Kitchen ConferenceHall Figure 1.37 A UML representation of classes LivingRoom and Cubicle, defined in separate packages, with their associations Class Cubicle can refer to class LivingRoom without using an import statement: package office; class Cubicle { home.LivingRoom livingRoom; } For no import statement, use fully qualified name to refer to LivingRoom from package home Class Cubicle can use the simple name for class LivingRoom by using the import statement: package office; import home.LivingRoom; Import statement class Cubicle { LivingRoom livingRoom; } No need to use fully qualified name of LivingRoom Licensed to Mark Watson 79 Packages NOTE The import statement doesn’t embed the contents of the imported class in your class, which means that importing more classes doesn’t increase the size of your own class. It lets you use the simple name for a class or interface defined in a separate package. 1.6.4 Using packages without using the import statement Classes in the java.lang package are automatically imported in all the Java classes, interfaces, and enums. To use simple names for classes, interfaces, and enums from other packages, you should use the import statement. It’s possible to use a class or interface from a package without using the import statement by using its fully qualified name: Missing import statement class AnnualExam { certification.ExamQuestion eq; } Define a variable of ExamQuestion by using its fully qualified name. But using a fully qualified class name can clutter your code if you use multiple variables of interfaces and classes defined in other packages. Don’t use this approach in real projects. For the exam, it’s important to note that you can’t use the import statement to use multiple classes or interfaces with the same names from different packages. For example, the Java API defines class Date in two commonly used packages: java.util and java.sql. To define variables of these classes in a class, use their fully qualified names with the variable declaration: Missing import statement class AnnualExam { java.util.Date date1; java.sql.Date date2; } Variable of type java.sql.Date Variable of type java.util.Date An attempt to use an import statement to import both these classes in the same class will not compile: import java.util.Date; import java.sql.Date; class AnnualExam { } Code to import classes with same name from different packages won’t compile In the preceding code, you want to use a shortcut (Date) but your shortcut refers to either java.util.Date or java.sql.Date. So the Java compiler has no way of knowing which is which (both have Date as their simple name), therefore the compiler error. Licensed to Mark Watson 80 CHAPTER 1 Java class design certification ExamQuestion MultipleChoice 1.6.5 Figure 1.38 A UML representation of the certification package Importing a single member versus all members of a package You can import either a single member or all members (classes and interfaces) of a package using the import statement. First, revisit the UML notation of the certification package, as shown in figure 1.38. Examine the following code for class AnnualExam: Imports only ExamQuestion import certification.ExamQuestion; class AnnualExam { ExamQuestion eq; MultipleChoice mc; Will not } compile Compiles okay By using the wildcard character, an asterisk (*), you can import all of the public members, classes, and interfaces of a package. Compare the previous class definition with the following definition of class AnnualExam: import certification.*; class AnnualExam { ExamQuestion eq; MultipleChoice mc; } Imports all classes and interfaces from certification Also compiles okay Compiles okay When you work with an IDE, it may automatically add import statements for classes and interfaces that you reference in your code. 1.6.6 The import statement doesn’t import the whole package tree You can’t import classes from a subpackage by using an asterisk in the import statement. For example, the UML notation in figure 1.39 depicts the package com.oracle .javacert with class Schedule and two subpackages, associate and webdeveloper. The associate package contains class ExamQuestion, and the webdeveloper package contains class MarkSheet. The following import statement will import only the Schedule class; it won’t import classes ExamQuestion and MarkSheet: import com.oracle.javacert.*; Imports Schedule only Licensed to Mark Watson 81 Packages com.oracle.javacert Schedule associate ExamQuestion webdeveloper MarkSheet Figure 1.39 A UML representation of the com.oracle.javacert package and its subpackages Similarly, the following import statement will import all the classes from the associate and webdeveloper packages: import com.oracle.javacert.associate.*; import com.oracle.javacert.webdeveloper.*; 1.6.7 Imports ExamQuestion only Imports MarkSheet only Importing classes from the default package What happens if you don’t include a package statement in your class or interface? In this case, they become part of a default, no-name package. This default package is automatically imported in the Java classes and interfaces defined within the same directory on your system. For example, classes Person and Office, which aren’t defined in an explicit package, can use each other if they’re defined in the same directory: class Person { // code } class Office { Person p; } Not defined in an explicit package Person accessible in Office Members of a named package can’t access classes and interfaces defined in the default package. EXAM TIP 1.6.8 Static imports You can import an individual static member of a class or an interface, or all its static members, by using the import static statement. Though accessible using an instance, the static members are usually accessed by prefixing their name with the class or interface names. By using static import, you can drop the prefix and just use the name of the static variable or method. Licensed to Mark Watson 82 CHAPTER 1 Java class design In the following code, class ExamQuestion defines a public static variable named marks and a public static method named print(): package certification; public class ExamQuestion { static public int marks; public static void print() { System.out.println(100); } } Public static variable marks Public static method print() Variable marks can be accessed in class AnnualExam using the import static statement. The order of the keywords import and static can’t be reversed: package university; import static certification.ExamQuestion.marks; class AnnualExam { AnnualExam() { Access variable marks marks = 20; without prefixing it } with its class name } EXAM TIP Correct statement is import static, not static import This feature is called static imports, but syntax is import static. To use all public and static members of class ExamQuestion in class AnnualExam without importing each of them individually, you can use an asterisk with the import static statement: package university; Imports all static import static certification.ExamQuestion.*; members of ExamQuestion class AnnualExam { AnnualExam() { marks = 20; Uses marks and print() without print(); prefixing them with their class names } } Because variable marks and method print() are public, they’re accessible to class AnnualExam. By using import static you don’t have to prefix them with their class name. But if they were defined using any other access modifier, they wouldn’t be accessible in AnnualExam because both these classes are defined in separate packages and AnnualExam doesn’t inherit ExamQuestion. 1.7 Summary This chapter covers the basic building blocks of the Java class design, starting with access modifiers, and then overloading and overriding methods, creating packages, and using classes from other packages. As a Java programmer, you should understand the role of access modifiers in designing your classes. We covered how access modifiers enable a class to control who can access it, to what extent, and how. Licensed to Mark Watson Review notes 83 Efficient design and implementation of an application also depends on correct and appropriate overloaded and overridden methods. You witnessed multiple examples on the need for overloading and overriding methods, including the correct ingredients. We also covered why all the methods of a base class can’t be overridden. A discussion of the nonfinal methods of class java.lang.Object, which is the parent class of all the Java classes, showed you why and how to override its methods. The methods of class Object are called by various other classes and JRE, which makes it crucial for a developer to override the relevant methods from class Object before shipping them off to be used by other people. You also learned how you can use casting to refer to specific behavior of derived class objects when they’re referred to their base class references. The instanceof operator is used to logically test whether an object is a valid type of a class or an interface. In the final section, we worked with package and import statements. It’s important to group your classes, interfaces, enums, and other Java entities depending on their functionality. In real programming projects, you’d always work with classes organized in packages. REVIEW NOTES This section lists the main points covered in this chapter. Java access modifiers ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ The access modifiers control the accessibility of your class and its members outside the class and package. Access modifiers defined by Java are public, protected, and private. In the absence of an explicit access modifier, a member is defined with the default access level. The public access modifier is the least restrictive access modifier. Classes and interfaces defined using the public access modifier are accessible to related and unrelated classes outside the package in which they’re defined. The members of a class defined using the protected access modifier are accessible to classes and interfaces defined in the same package and to all derived classes, even if they’re defined in separate packages. The members of a class defined without using an explicit access modifier are defined with package accessibility (also called default accessibility). The members with package access are accessible only to classes and interfaces defined in the same package. A class defined using default access can’t be accessed outside its package. The private members of a class are only accessible to itself. The private access modifier is the most restrictive access modifier. A top-level class, interface, or enum can only be defined using the public or default access. They can’t be defined using protected or private access. Licensed to Mark Watson 84 CHAPTER 1 Java class design ■ ■ Method parameters and local variables can never be defined using an explicit access modifier. They don’t have access control–only scope. Either they’re in scope or out of scope. If accessibility of an existing Java entity or its member is decreased, it can break others’ code. Overloaded methods and constructors ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ Overloaded methods are methods with the same name but different method parameter lists. A class can overload its own methods and inherited methods from its base class. Overloaded methods accept different lists of arguments. The argument lists of overloaded methods can differ in terms of change in the number, type, or position of parameters that they accept. Overloaded methods are bound at compile time. Unlike overridden methods they’re not bound at runtime. A call to correctly overloaded methods can also fail compilation if the compiler is unable to resolve the call to an overloaded method. Overloaded methods might define a different return type or access or nonaccess modifier, but they can’t be defined with only a change in their return types or access or nonaccess modifiers. Overloaded constructors must be defined using different argument lists. Overloaded constructors can’t be defined by just a change in the access modifiers. Overloaded constructors can be defined using different access modifiers. A constructor can call another overloaded constructor by using the keyword this. A constructor can’t invoke another constructor by using its class’s name. If present, the call to another constructor must be the first statement in a constructor. Method overriding and virtual method invocation ■ ■ ■ ■ ■ ■ Method overriding is an OOP language feature that enables a derived class to define a specific implementation of an existing base class method to extend its own behavior. A derived class can override an instance method defined in a base class by defining an instance method with the same method signature. Whenever you intend to override methods in a derived class, use the annotation @Override. It will warn you if a method can’t be overridden or if you’re actually overloading a method rather than overriding it. Overridden methods can define the same or covariant return types. A derived class can’t override a base class method to make it less accessible. Overriding methods must define exactly the same method parameters; the use of a subclass or parent class results in overloading methods. Licensed to Mark Watson Sample exam questions ■ ■ ■ ■ ■ ■ 85 Static methods can’t be overridden. They’re not polymorphic and they’re bound at compile time. In a derived class, a static method with the same signature as that of a static method in its base class hides the base class method. A derived class can’t override the base class methods that aren’t accessible to it, such as private methods. Constructors cannot be overridden because a base class constructor isn’t inherited by a derived class. A method that can be overridden by a derived class is called a virtual method. Virtual method invocation is invocation of the correct method–determined using the object type and not its reference. Java packages ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ You can use packages to group together a related set of classes and interfaces. The package and subpackage names are separated using a period. Classes and interfaces in the same package can access each other. An import statement allows the use of simple names for classes and interfaces defined in other packages. You can’t use the import statement to access multiple classes or interfaces with the same names from different packages. You can import either a single member or all members (classes and interfaces) of a package using the import statement. You can’t import classes from a subpackage by using the wildcard character, an asterisk (*), in the import statement. A class from the default package can’t be used in any named package, regardless of whether it’s defined within the same directory or not. You can import an individual static member of a class or all its static members by using an import static statement. An import statement can’t be placed before a package statement in a class. Any attempt to do so will cause the compilation of the class to fail. The members of the default package are accessible only to classes or interfaces defined in the same directory on your system. SAMPLE EXAM QUESTIONS Q 1-1. Which of the following points should you incorporate in your application design? a b c d Create related classes in a single package. Don’t make derived classes overload methods from their base class. Expose the functionality of your classes using public methods. Create private methods to work as helper methods for the public methods. Licensed to Mark Watson 86 CHAPTER 1 Java class design Q 1-2. What is the output of the following code? class Wood { public Wood() { System.out.println("Wood"); } { System.out.println("Wood:init"); } } class Teak extends Wood { { System.out.println("Teak:init"); } public Teak() { System.out.println("Teak"); } public static void main(String args[]) { new Teak(); } } a Wood:init Wood Teak:init Teak b Wood Wood:init Teak:init Teak c Wood:init Teak:init Wood Teak d Wood Wood:init Teak Teak:init Q 1-3. Examine the following code and select the answer options that are correct individually. class Machine { void start() throws Exception { System.out.println("start machine"); } } class Laptop { void start() { System.out.println("Start Laptop"); } void start(int ms) { System.out.println("Start Laptop:"+ms); } } a b c Class Laptop overloads method start(). Class Laptop overrides method start(). Class Machine overrides method start(). Licensed to Mark Watson Sample exam questions d e 87 Class Machine won’t compile. Class Laptop won’t compile. Q 1-4. Given that classes Class1 and Class2 exist in separate packages and source code files, examine the code and select the correct options. package pack1; public class Class1 { protected String name = "Base"; } package pack2; import pack1.*; class Class2 extends Class1{ Class2() { Class1 cls1 = new Class1(); name = "Derived"; System.out.println(cls1.name); } } a b c d e f //line 1 //line 2 //line 3 Class2 can extend Class1 but it can’t access the name variable on line 2. Class2 can’t access the name variable on line 3. Class2 can’t access Class1 on line 1. Class2 won’t compile. Line 3 will print Base. Line 3 will print Derived. Q 1-5. Select the correct option. a b c d The declaration of private variables to store the state of an object is encouraged. The protected members of a class aren’t accessible outside the package in which the class is defined. The public members of a class that’s defined with default access can be accessed outside the package. If you change the signature or implementation of a private method, other classes that use this method cease to compile. Q 1-6. Given the following code interface Scavenger{} class Bird{} class Parrot extends Bird{} class Vulture extends Bird implements Scavenger{} class BirdSanctuary { public static void main(String args[]) { Bird bird = new Bird(); Parrot parrot = new Parrot(); Licensed to Mark Watson 88 CHAPTER 1 Java class design Vulture vulture = new Vulture(); //INSERT CODE HERE } } In which of the following options will the code, when inserted at //INSERT CODE HERE, throw a ClassCastException? a b c d Vulture vulture2 = (Vulture)parrot; Parrot parrot2 = (Parrot)bird; Scavenger sc = (Scavenger)vulture; Scavenger sc2 = (Scavenger)bird; Q 1-7. Assuming that all of the following classes are defined in separate source code files, select the incorrect statements. package solarfamily; public class Sun { public Sun() {} } package stars; public class Sun { public Sun() {} } package skyies; import stars.Sun; import solarfamily.Sun; class Sky { Sun sun = new Sun(); } a b c d e // line1 // line2 // line 3 Code compilation fails at line 1. Code compilation fails at line 2. Code compilation fails at line 3. The code compiles successfully and class Sky creates an object of class Sun from the stars package. The code compiles successfully and class Sky creates an object of class Sun from the solarfamily package. Q 1-8. Select the correct options. class Color { String name; Color(String name) {this.name = name;} public String toString() {return name;} public boolean equals(Object obj) { return (obj.toString().equals(name)); } } Licensed to Mark Watson Sample exam questions a b c d e 89 Class Color overrides method toString() correctly. Class Color overrides method equals() correctly. Class Color fails to compile. Class Color throws an exception at runtime. None of the above. Q 1-9. Given the following code class Book { String isbn; Book(String isbn) {this.isbn = isbn;} public int hashCode() { return 87536; } } Select the correct option. a b c d Objects of the class Book can never be used as keys because the corresponding objects wouldn’t be retrievable. Method hashCode() is inefficient. Class Book will not compile. Though objects of class Book are used as keys, they will throw an exception when the corresponding values are retrieved. Q 1-10. What is the output of the following code? class Wood { String wood = "Wood"; public Wood() { wood = "Wood"; } { wood = "init:Wood"; } } class Teak extends Wood { String teak; { teak = "init:Teak"; } public Teak() { teak = "Teak"; } public static void main(String args[]) { Teak teak = new Teak(); System.out.println(teak.wood); System.out.println(teak.teak); } } Licensed to Mark Watson 90 CHAPTER 1 Java class design a init:Wood init:Teak b init:Wood Teak c Wood init:Teak d Wood Teak Q 1-11. Given the following code class Cloth {} class Shirt extends Cloth implements Resizable{} class Shorts extends Cloth {} interface Resizable {} class Factory { public static void main(String sr[]) { Shirt s = new Shirt(); //INSERT CODE HERE System.out.println(res); } } Which options will print true? a boolean res = new Cloth() instanceof Shirt; b boolean res = new Shirt() instanceof Resizable; c boolean res = null instanceof Factory; d Cloth cloth = new Cloth(); Shirt shirt = new Shirt(); boolean res = shirt instanceof cloth; ANSWERS TO SAMPLE EXAM QUESTIONS A 1-1. a, c, d [1.1] Use access modifiers: private, protected, and public [1.3] Overload constructors and methods [1.7] Use package and import statements Explanation: Option (a) is correct. A package enables you to create a namespace to group related classes and interfaces together. Option (b) is incorrect. A base class overloads its base class method, as required. Making derived classes overload their base class methods doesn’t make it an incorrect or inefficient design. Options (c) and (d) are also correct. The functionality of your classes should be exposed using the public methods. The private methods are called within the class in which they’re defined. They usually work as helper methods. Licensed to Mark Watson Answers to sample exam questions 91 A 1-2. a [1.3] Overload constructors and methods Explanation: When a class is compiled, the contents of its initializer block are added to its constructor, just before its own contents. For example, here’s the decompiled code for class Wood. As you can see, the contents of its initializer block are added to its constructor: class Wood { public Wood() { System.out.println("Wood:init"); System.out.println("Wood"); } } A 1-3. a [1.2] Override methods [1.3] Overload constructors and methods Explanation: Class Laptop correctly overloads the method start() by defining a different parameter list. Options (b) and (c) are incorrect because classes Laptop and Machine are unrelated. A derived class can override its base class method. Method start() qualifies as a valid overridden method in class Laptop, if Laptop extends class Machine. It’s acceptable for an overriding method to not throw any checked exception, even if the base class method is throwing a checked exception. Options (d) and (e) are incorrect because both classes will compile successfully. A 1-4. b, d [1.7] Use package and import statements Explanation: A derived class can access a protected member of its base class, across packages, directly. But if the base and derived classes are in separate packages, then you can’t access protected members of the base class by using reference variables of class Base in a derived class. So, Class2 doesn’t compile. Options (e) and (f) are incorrect because Class2 won’t compile. A 1-5. a [1.1] Use access modifiers: private, protected, and public [1.7] Use package and import statements Explanation: Option (b) is incorrect because the protected members of a class are accessible by the derived classes, outside the package in which the class is defined. Licensed to Mark Watson 92 CHAPTER 1 Java class design Option (c) is incorrect because a class with default access isn’t visible outside the package within which it’s defined. If the class isn’t visible itself, it doesn’t matter whether its members are accessible or not. Option (d) is incorrect because a private method can’t be used outside the class in which it’s defined. A 1-6. b, d [1.4] Use the instanceof operator and casting Explanation: ClassCastException is thrown at runtime. So the options that don’t fail to compile are eligible to be considered for the following question: Will they throw a ClassCastException? Option (a) is incorrect because it fails to compile. Option (b) is correct because classes Bird and Parrot are in the same hierarchy tree, so an object of base class Bird can be explicitly casted to its derived class Parrot at compilation. But the JVM can determine the type of the objects at runtime. Because an object of a derived class can’t refer to an object of its base class, this line throws a ClassCastException at runtime. Option (c) is incorrect because class Vulture implements the interface Scavenger, so this code will also execute without the explicit cast. Option (d) is correct. An instance of a nonfinal class can be casted to any interface type using an explicit cast during the compilation phase. But the exact object types are validated during runtime and a ClassCastException is thrown if the object’s class doesn’t implement that interface. Class Bird doesn’t implement the interface Scavenger and so this code fails during runtime, throwing a ClassCastException. A 1-7. b [1.7] Use package and import statements Explanation: Class Sky fails with the following error message: Sky.java:3: error: stars.Sun is already defined in a single-type import import solarfamily.Sun; ^ 1 error A 1-8. a [1.2] Override methods Explanation: Class Color overrides method toString() correctly, but not method equals(). According to the contract of method equals(), for any non-null reference Licensed to Mark Watson 93 Answers to sample exam questions values x and y, x.equals(y) should return true if and only if y.equals(x) returns true—this rule states that two objects should be comparable to each other in the same way. Class Color doesn’t follow this rule. Here’s the proof: class TestColor { public static void main(String args[]) { Color color = new Color("red"); String string = "red"; System.out.println(color.equals(string)); System.out.println(string.equals(color)); // prints true // prints false } } A 1-9. b [1.6] Override the hashCode, equals, and toString methods from the Object class to improve the functionality of your class Explanation: Method hashCode() returns the same hash code for all the objects of this class. This essentially makes all the values be stored in the same bucket if objects of the preceding classes are used as keys in class HashMap (or similar classes that use hashing), and reduces it to a linked list, drastically reducing its efficiency. Option (a) in incorrect. Book instances can be used to retrieve corresponding key values but only in limited cases—when you use the same keys (instances) to store and retrieve values. Even though hashCode() will return the same value for different Book instances, equals() will always compare the reference variables and not their values, returning false. A 1-10. d [1.3] Overload constructors and methods Explanation: When a class is compiled, the contents of its initializer block are added to its constructor just before its own contents. For example, here’s the decompiled code for class Wood. As you can see, the contents of its initializer block are added to its constructor: class Wood { public Wood() { wood = "Wood"; wood = "init:wood"; wood = "Wood"; } String wood; } // initial initialization // re-assignment by the initializer block // re-assignment by the constructor Licensed to Mark Watson 94 CHAPTER 1 Java class design A 1-11. b [1.4] Use the instanceof operator and casting Explanation: Option (a) prints false. Option (c) prints false. It doesn’t fail to compile because null is a valid literal value that can be used for objects. Option (d) fails to compile. The instanceof operator must be followed by the name of an interface, class, or enum. Licensed to Mark Watson Advanced class design Exam objectives covered in this chapter What you need to know [2.1] Identify when and how to apply abstract classes The design requirements and implications of using abstract classes in your application. [2.2] Construct abstract Java classes and subclasses Construction and inheritance with abstract Java classes. [2.3] Use the static and final keywords The need for defining static and final members (classes, methods, initializer blocks, and variables). The implications of defining nonstatic/nonfinal members as static/final members, and vice versa. [2.4] Create top-level and nested classes The flavors of nested classes—inner, static nested, method local, and anonymous. The design benefits, advantages, and disadvantages of creating inner classes. How each type of nested class is related to its outer class. The access and nonaccess modifiers that can be used with the definition of these classes and their members. [2.5] Use enumerated types How to compare enumerated types with regular classes. How to define enums with constructors, variables, and methods. How to define enums within classes, interfaces, and methods. How to override methods of a particular enum constant. Use of variables of enum types—when to use the enum name and when to leave it. Use of enumerated types in switch constructs. The default methods available to all enums. 95 Licensed to Mark Watson 96 CHAPTER 2 Advanced class design While designing your application, you might need to answer questions like these: ■ ■ ■ ■ ■ How do I ensure that a derived class implements an inherited behavior in its own specific manner? When do I prevent my class from being extended or methods from being overridden? When do I make objects share the same copy of a variable and when do I provide them with their own separate individual copy? When do I create an inner class to perform a set of related tasks and when do I let the top-level class handle it? How do I define constants by using enums? Design decisions require insight into the benefits and pitfalls of multiple approaches. When armed with adequate information, you can select the best practices and approaches to designing your classes and application. The topics covered in this chapter will help you answer the aforementioned questions. I’ll take you through examples and give you multiple choices to help you determine the best option for designing your classes. This chapter covers ■ ■ ■ ■ Abstract classes Keywords static and final Enumerated types Nested and inner classes EXAM TIP Take note of the relationship between an exam objective heading and its subobjectives. For example, the topics of using the static and final keywords, using enumerated types, and creating toplevel and nested classes are included within the main objective advanced class design. So, apart from using the correct syntax of all of these, the exam will query you on the impact of their use on the design of a class and an application. Let’s start with the first exam objective in this chapter, identifying when and how to apply abstract classes. Licensed to Mark Watson Abstract classes and their application 2.1 97 Abstract classes and their application [2.1] Identify when and how to apply abstract classes [2.2] Construct abstract Java classes and subclasses Imagine you’re asked to bring a bouquet of flowers. Because no particular flower is specified, you can choose any flower. How is the term flower used here? It communicates a group of properties and behavior, which are applicable to multiple types of flowers. Flowers like tulip, rose, hibiscus, and lotus, though similar, are also unique. In this example, you can compare the term flower to an abstract class: the term captures basic properties and behavior, yet enforces individual flower types to implement some of that behavior in a unique manner—all flowers must have petals, though of different size, color, or shape. In this section, we’ll focus on how the exam will test you on identifying abstract classes, and understanding their need, construction, use, and application. We’ll also cover the dos and don’ts of creating abstract classes. For the exam, it’s important to compare the similarities and differences of abstract classes and concrete classes. These differences affect the creation and use of these classes. Let’s start by identifying abstract classes. 2.1.1 Identify abstract classes An abstract class is an incomplete class or is considered to be incomplete. You define it by using the keyword abstract. You can’t instantiate an abstract class, but you can subclass it to create abstract or concrete derived classes. The choice of defining an abstract class depends on the application context in which the classes are created; it all depends on the details that you need for a class in an application. For example, a class Animal might be defined as an abstract class in one application but not in another. Imagine that you need to create a simple application, GeoAnimals, which helps young children identify a predefined set of common wild animals, while including basic information like the food the animals eat and their habitat. Figure 2.1 shows (a Lion Tiger Elephant food:String avgLife:double food:String avgLife:double striped:boolean food:String avgLife:double eat() live() eat() live() eat() live() moveTrunk() Figure 2.1 Classes Lion, Tiger, and Elephant identified for creating the application GeoAnimals Licensed to Mark Watson 98 CHAPTER 2 Advanced class design Animal food:String avgLife:double eat() live() < > Lion Tiger Elephant striped:boolean moveTrunk() Figure 2.2 Classes Lion, Tiger, and Elephant inherit class Animal. few) classes—Lion, Elephant, and Tiger—that you might identify for this application. I deliberately limited the number of classes to keep the example simple. As you can see, classes Lion, Tiger, and Elephant have common attributes and behavior. Let’s pull out another generic class—say, Animal—and make the rest of the classes extend it. Figure 2.2 shows the new arrangement. Now the big question: Do you need to define the base class Animal as an abstract class? How can you determine this? You can ask yourself simple questions to answer the big question: ■ ■ Should my application be allowed to create instances of the generic class Animal? If no, define class Animal as an abstract class. Does class Animal include behavior that’s common to all its derived classes, but can’t be generalized (must it be implemented by the derived classes in their own specific manner)? If yes, define the relevant method as an abstract method and class Animal as an abstract class. In this sample application, you’d never need objects of class Animal because they would always refer to a specific type of animal. So class Animal qualifies to be defined as an abstract class. Also, eating behavior, though common to all the animals, is unique to every specific animal. So method eat() is a perfect candidate to be defined as an abstract method. Figure 2.3 shows the new arrangement, where class Animal is defined as an abstract class, and method eat() is defined as an abstract method. Now all the derived classes must implement method eat(). Because an abstract class is meant to be extended by other classes, and its abstract methods are meant to be implemented, it’s recommended that you document its expected behavior in your real-life projects. This documentation will enable your class to be inherited and used appropriately. EXAM TIP An abstract method doesn’t define an implementation. It enforces all the concrete derived classes to implement it. Licensed to Mark Watson Abstract classes and their application Animal food:String avgLife:double eat() live() 99 Abstract base class Abstract method < > Lion Tiger Elephant eat() striped:boolean moveTrunk() eat() eat() Figure 2.3 Abstract class Animal defines an abstract method eat() and is inherited by classes Lion, Tiger, and Elephant. Until this point, you’ve looked at how to identify an abstract class. Does that imply that if you were to define class Animal in another application, you’d define it as an abstract class? Not always. For example, an application that counts all living beings, categorized as humans, animals, and plants, might not need to define class Animal as an abstract class because the application might not need to create its specific types; it needs only a count of the total animals. If you need to store the type of an animal, class Animal can define an attribute—say, species. This arrangement is shown in figure 2.4. Another frequently asked question by new programmers or designers is, when is an abstract base class fit to be defined as an interface? Interfaces can be defined only when no implementation of any method is provided. Also, an interface can define only constants, which can’t be reassigned another value by the implementing classes. The base class Animal discussed previously can’t be defined as an interface; it can’t define its attributes food and avgLife as constants. As an example of an interface, the Java package java.util contains multiple interfaces, such as List. The interface List defines multiple methods, which must be implemented by all the implementing classes, such as ArrayList. LivingBeing Human Animal Plant species:String Figure 2.4 Class Animal need not be always defined as an abstract class in all applications. Licensed to Mark Watson 100 CHAPTER 2 Advanced class design Starting with Java 8, an interface can define a default implementation of its methods, so an implementing class might not necessarily override these methods. But this exam is based on Java 7 and I’ll continue to refer to an interface as the one that can’t define method implementation. NOTE Now that you understand how to identify abstract classes, let’s look at how to construct abstract classes and their subclasses, and how to apply them. On the exam, you’ll be questioned on correct construction of abstract classes, their subclasses, and their dos and don’ts. 2.1.2 Construct abstract classes and subclasses To keep the code small, let’s code the abstract class Animal and only two of its derived classes, Lion and Elephant: b abstract class Animal { protected String food; protected double avgLife; Abstract base class Animal Animal(String food, double avgLife) { this.food = food; this.avgLife = avgLife; } abstract void eat(); c d Properties of class Animal Constructor e Abstract method eat() void live() { System.out.println("Natural habitat : forest"); } f Nonabstract method live() } At B, abstract class Animal is defined by prefixing the class definition with the keyword abstract. The code at c defines attributes to store values for food and average life span: food and avgLife. The code at d defines a constructor for class Animal. You can’t instantiate an abstract class, but you can create its constructors, including overloaded constructors. At least one of the Animal constructors must be called by instances of its derived classes. The code at e defines abstract method eat(), which delegates the responsibility of implementing it to the derived classes. You can define class Animal as an abstract class, even if doesn’t define any abstract methods. The code at f defines method live(), with an implementation. If required, it can be overridden by the derived classes. It isn’t obligatory for abstract classes to define abstract methods. Abstract methods must not define a body. EXAM TIP Licensed to Mark Watson 101 Abstract classes and their application Following is the definition of derived class Lion: class Lion extends Animal{ Lion(String food, double avgLife) { super(food, avgLife); } void eat() { System.out.println("Lion-hunt " + food); } } b Constructor c Implement method eat() Class Lion extends the base class Animal. It defines a constructor at B, which accepts a double value for average life and a String value for food and passes it on to its base class’s constructor. At c, class Lion implements method eat(). Let’s now define class Elephant: class Elephant extends Animal{ Elephant(String food, double avgLife) { super(food, avgLife); } b Constructor void eat() { System.out.println("Elephant-method eat"); } c void moveTrunk() { System.out.println("Elephant-method moveTrunk"); } Implement method eat() d New method moveTrunk() } At B, class Elephant defines a constructor that calls its base class constructor. At c, it implements abstract method eat() from the base class. At d, it defines a new method, moveTrunk(). Notice the power of base class constructors to ensure that all derived class constructors pass them a value. The base class Animal defines only one constructor that accepts a value for its instance variables food and avgLife. Because a derived class constructor must call its base class’s constructor, classes Lion and Elephant define a constructor that calls Animal’s constructor. EXAM TIP Let’s put all these classes to work, in class GeoAnimals, as follows: class GeoAnimals{ Animal[] animals = new Animal[2]; b An array of type Animal—base class of Lion and Elephant GeoAnimals() { animals[0] = new Lion("Antelope", 20); animals[1] = new Elephant("Bananas", 60); } c Initialize array animals with separate instances of Lion and Elephant. Licensed to Mark Watson 102 CHAPTER 2 Advanced class design void flashcards() { for (Animal anAnimal : animals) { anAnimal.eat(); anAnimal.live(); } } d public static void main(String args[]) { GeoAnimals myAnimals = new GeoAnimals(); myAnimals.flashcards(); } Iterate through objects of array animals, calling methods eat() and live(). e Create an instance of GeoAnimals and call method flashcards(). } Here’s the output of the preceding code (blank lines were added to improve readability): Lion-hunt Antelope Natural habitat : forest Elephant-method eat Natural habitat : forest Let’s walk through this code. The code at B declares an array of type Animal. Though you can’t create instances of abstract class Animal, an array of Animal can be used to store objects of its derived classes, Lion and Elephant. The code at c initializes animals with instances of classes Lion and Elephant. The code at d iterates through the array animals, calling methods eat() and live() on all its elements. The code at e defines method main() that creates an object of class GeoAnimals, calling method flashcards(). The code in this section walked you through how to create abstract classes and their subclasses, and how to use them. The efficient use of abstract classes lies in their identification in an application. Let’s see how well you score on identifying all abstract and concrete classes in an application in the following “Twist in the Tale” exercise. Twist in the Tale 2.1 The following are names of multiple classes. Your task is to arrange these in an inheritance hierarchy, connecting all base and derived classes. At end of the exercise, all these classes should be connected, with the base class at the top and derived classes below it. Lion Omnivore Animal Dog Cat Carnivore Tiger Herbivore Deer Elephant Licensed to Mark Watson 103 Abstract classes and their application Here’s another example that will help you attempt the preceding exercise. Book Fiction Book CourseBook StoryBook History StoryBook CourseBook Geology NonFiction Fiction NonFiction History Geology < > An abstract method can’t be defined in a concrete class. It can be defined in an abstract class only. EXAM TIP 2.1.3 Understand the need for abstract classes An abstract class represents partial implementation of an object or concept. But why do you need partial implementation? Do abstract classes exist only so other classes can inherit them? These questions are frequently asked by new Java application designers. You might also have to answer these questions on the exam. You need an abstract class to pull out and group together the common properties and behavior of multiple classes—the same reason you need a nonabstract base class. You define a base class as an abstract class to prevent creation of its instances. As the creator, you think that it doesn’t include enough details to create its own objects. When you define abstract methods in a base class, it forces all its nonabstract derived classes to implement the incomplete functionality (abstract methods) in their own unique manner. Because you can’t create instances of an abstract class, there’s not much sense in creating an abstract base class, which isn’t extended by other classes. Abstract classes make a point loud and clear: they force the concrete derived classes to implement a base class’s abstract methods, in their own unique manner. EXAM TIP Note that I haven’t discussed the need for, advantages of, or disadvantages of creating nonabstract base classes in this section. This section specifically covers base classes that are abstract. 2.1.4 Follow the dos and don’ts of creating and using abstract classes Apart from the points covered in the previous section, the exam will likely include other theoretical and coding questions on the dos and don’ts of creating and implementing abstract classes. Licensed to Mark Watson 104 CHAPTER 2 Advanced class design DON’T CREATE AN ABSTRACT CLASS ONLY TO PREVENT CREATION OF ITS OBJECTS To prevent instantiation of a class by using the operator new, define all its class constructors as private. For example, class java.lang.Math in the Java API doesn’t allow creation of its objects by defining its constructor as a private member: package java.lang; public final class Math{ private Math() { /*code */} } DON’T MAKE AN ABSTRACT CLASS IMPLEMENT INTERFACES THAT RESULT IN INVALID METHOD IMPLEMENTATION When a class implements an interface, the class must implement its methods (unless the class is abstract) to meet the contract. But if the class defines methods with the same name as the one defined in the interface, they should either comply with correct method overriding or overloading rules or else the class won’t compile. In the following example, class Animal can’t implement interface Live: interface Live{ boolean eat(); } Method eat() that returns boolean value abstract class Animal implements Live{ public abstract void eat(); } Won’t compile; method eat() from Live and Animal can’t coexist. Method eat() doesn’t return any value. Class Animal won’t compile because method eat() from interface Live and method eat() defined in class Animal exist as invalid overloaded methods. DON’T CREATE OBJECTS OF AN ABSTRACT CLASS Code that creates objects of an abstract class won’t compile: abstract class Animal{} class Forest { Animal animal = new Animal(); } Won’t compile; can’t instantiate abstract classes. DON’T DEFINE AN ABSTRACT CLASS AS A FINAL CLASS A final class can’t be extended. On the other hand, abstract classes are created so they can be extended by other classes. Hence, abstract classes can’t be defined as final classes. abstract final class Animal {} Won’t compile Licensed to Mark Watson 105 Abstract classes and their application DON'T FORCE AN ABSTRACT CLASS TO IMPLEMENT ALL METHODS FROM THE INTERFACE(S) IT IMPLEMENTS An abstract class can implement multiple interfaces. It might not implement all the abstract methods from the implemented interface(s), leaving them to be implemented by all its nonabstract derived classes: interface Live{ void eat(); } abstract class Animal implements Live{} Abstract class Animal doesn’t implement eat() from interface Live. DO USE AN OBJECT OF AN ABSTRACT CLASS TO REFER TO OBJECTS OF ITS NONABSTRACT DERIVED CLASSES An abstract class can’t be instantiated. But this doesn’t stop you from using a reference variable of an abstract base class to refer to an instance of its nonabstract derived class: abstract class Animal{} class Deer extends Animal{} class Forest{ Animal animal = new Deer(); } Abstract class variable can refer to instance of its derived class Comparing an abstract class with a concrete class is obvious, as covered in the next section. This comparison will help you with multiple exam objectives: identifying abstract classes, their construction, and their application. 2.1.5 Compare abstract classes and concrete classes Do you think the constructor of an abstract base class is called in the same manner as that of a concrete base class? Yes, indeed. Table 2.1 answers many more questions like this by comparing abstract and concrete classes. Table 2.1 Comparing an abstract class with a concrete class Comparison Category Abstract class Concrete class Create a new type ✓ ✓ Use as base class ✓ ✓ Extend another class ✓ ✓ Implement interfaces ✓ ✓ Define attributes and concrete methods ✓ ✓ Require at least one constructor to be called by its derived classes ✓ ✓ Define abstract methods ✓ ✗ Allow object creation ✗ ✓ Licensed to Mark Watson 106 CHAPTER 2 Advanced class design Before moving on to the next section, let’s quickly list the points to remember about abstract classes for the exam. Rules to remember for creating abstract classes ■ ■ ■ ■ ■ ■ ■ ■ ■ An abstract class must be defined by using the keyword abstract. An abstract class can extend any other abstract or concrete class and implement other interfaces. An abstract class can define multiple constructors. An abstract class can define instance and static variables. An abstract class can define instance and static methods. An abstract class might not necessarily define an abstract method and can exist without any abstract method. A class can’t define an abstract static method. Don’t create an abstract class just to prevent creation of its instances. Don’t make an abstract class implement interfaces that result in incorrect overloaded or overridden methods. Rules to remember for subclassing an abstract class ■ ■ ■ A concrete subclass must implement all the abstract methods in its abstract superclass(es). An abstract subclass might not implement all the abstract methods in its abstract superclass(es). A subclass must call at least one constructor from its superclass. Identification of abstract classes is an important design decision. It changes how other classes might use the abstract class. Similarly, creating classes that can’t be extended, creating methods that can’t be overridden, or creating class (or static) members are other important design decisions. In the next section, you’ll see how you can do so by using the static and final nonaccess modifiers. 2.2 Static and final keywords [2.3] Use the static and final keywords Defining a class as a final class prevents it from being extended. Similarly, a static variable or method can be accessed without instances of its class; the variable or method is available after its class is loaded into memory. These are a few examples of how the nonaccess modifiers static and final change the default behavior of a Java entity. For the exam, you need to understand the need for defining static and final members (classes, methods, initializer blocks, and variables) together with their correct definition Licensed to Mark Watson 107 Static and final keywords and use. You also need to know the implications of defining nonstatic/nonfinal members as static/final members, and vice versa. 2.2.1 Static modifier You can define variables, methods, nested classes, and nested interfaces as static members. They belong to a class and not to instances. They can be accessed soon after their class is loaded into memory. Top-level classes, interfaces, and enums can’t be defined as static entities. Watch out for code that declares top-level classes, interfaces, and enums as static members. Such code won’t compile. Let’s get started with static class variables. STATIC VARIABLES Static variables belong to a class and are shared by all its instances. Their value is the same for all instances of their class. A static class variable is created when its class is loaded into memory by the JVM. It can exist and is accessible even if no instances of the class exist. So you can use it to perform operations that span multiple instances of a class. Class Book defines a static class variable bookCount, to count the instances of class Book that are created while your program is running: class Book { static int bookCount; public Book() { ++bookCount; } } Static variable bookCount bookCount is incremented in constructor class Publisher{ public static void main(String args[]){ System.out.println(Book.bookCount); Book b1 = new Book(); Book b2 = new Book(); System.out.println(Book.bookCount); } } b Prints “0” c Prints “2” Assuming that no instances of Book were created earlier, the code at B prints 0. The code at c prints 2 due to creation of two instances of class Book, created on the preceding lines. Each invocation of the construction increments the value of the static class variable bookCount by 1. EXAM TIP Unlike instance variables, which are initialized for each instance, static class variables are initialized only once, when they are loaded into memory. The default variable values are false for boolean; '\u0000' for char; 0 for byte; short, int, 0L for long; 0.0F for float; 0.0D for double; and null for objects. Because the same value of a static class variable is shared across all the instances of a class, if modified, the same modified value is reflected across all instances. In the Licensed to Mark Watson 108 CHAPTER 2 Advanced class design following code, the value of the static class variable bookCount is accessed and modified using the class name Book and instances b1 and b2 (modifications in bold): class Book { static int bookCount; public Book() { ++bookCount; } } class Publisher{ public static void main(String args[]){ System.out.println(Book.bookCount); Book b1 = new Book(); Book b2 = new Book(); System.out.println(Book.bookCount); b1.bookCount = 10; System.out.println(b2.bookCount); } } Prints “0” (access bookCount using class name Book) Set value of bookCount to 10, using reference variable b1. Prints “10” (access bookCount using reference variable b2) NOTE For simplicity, I’ve defined the variable bookCount with default access, which is directly accessed and manipulated outside the class Book. This isn’t a recommended approach in real-life projects. Encapsulate your data by defining the class and instance variables as private and make them accessible outside their class through accessor and mutator methods. On the exam, you’re likely to see code that accesses a static class variable by using the name of its class and its instances. Although a static class variable is allowed to be accessed by using instances of a class, it’s not a preferred approach; it makes the static class variable seem to belong to an instance, which is incorrect. Always refer to a static class member by using its class name. You can access a static member by using the name of its class or any of its instances. All these approaches refer to the same static member. The preferred approach is to use a class name; otherwise, a static member seems to be tied to an instance, which is incorrect. EXAM TIP A combination of the static and final nonaccess modifiers is used to define constants (variables whose value can’t change). In the following code, the class Emp defines the constants MIN_AGE and MAX_AGE: class Emp { public static final int MIN_AGE = 20; static final int MAX_AGE = 70; } Constant MIN_AGE Constant MAX_AGE Licensed to Mark Watson Static and final keywords 109 STATIC METHODS Static methods don’t need instances of a class. They can be called even if no instance of the class exists. You define static methods to access or manipulate static class variables. The static methods can’t access nonstatic fields or nonstatic methods. Referring to the example of class Book, which used the static variable bookCount to count all instances of class Book, static methods getBookCount() and incrementBookCount() can be created to access bookCount and manipulate it: class Book { private static int bookCount; public static int getBookCount(){ return bookCount; } public void incrementBookCount() { ++bookCount; } Static method to retrieve value of static variable bookCount Static method to increment value of static variable bookCount } You also use static methods to define utility methods—methods that usually manipulate the method parameters to compute and return an appropriate value: static double average(double num1, double num2, double num3) { return(num1+num2+num3)/3; } A static method might not always define method parameters. For example, the method random in class java.lang.Math doesn’t accept any parameters. It returns a pseudorandom number, greater than or equal to 0.0 and less than 1.0. A static method is used to manipulate static class variables or to define utility methods. A utility method may or may not accept method parameters. EXAM TIP WHAT CAN A STATIC METHOD ACCESS? Neither static class methods nor static class variables can access the nonstatic instance variables and instance methods of a class. But the reverse is true: nonstatic variables and methods can access static variables and methods because the static members of a class exist even if no instances of the class exist. Static members are forbidden from accessing instance methods and variables, which can exist only if an instance of the class is created. Examine the following code: class MyClass { static int x = count(); int count() { return 10; } } Compilation error Licensed to Mark Watson 110 CHAPTER 2 Advanced class design This is the compilation error thrown by the previous class: MyClass.java:3: nonstatic method count() cannot be referenced from a static context static int x = count(); ^ 1 error The following code is valid: Static variable referencing class MyClass { a static method static int x = result(); static int result() { return 20; } int nonStaticResult() { return result(); } Nonstatic method } using a static method You can use constructors or instance initializer blocks to initialize the instance variables. But how can you initialize the static variables, after they’re loaded into memory? Static initializer blocks are the answer. STATIC INITIALIZER BLOCKS A static initializer block is a code block defined using braces and prefixed by the keyword static: static { //code to initialize static variables } Because static variables can’t be initialized using the constructors of a class, a static initializer block is used to initialize static variables. This initializer block executes when a class is loaded by the JVM into memory. You can define multiple static initializer blocks in your code, which execute in the order of their appearance. All types of statements are allowed in this block, including declaration, initialization, assignment, and calling of other static variables and methods. In the following example, class AffiliateProgram defines a static variable accountOpenBonus. The variable accountOpenBonus is initialized using a static initializer block: class AffiliateProgram { private static int accountOpenBonus; static { accountOpenBonus = 5; } } Declare static variable Initialize static variable using a static initializer block You might argue that you could initialize the static variable accountOpenBonus as follows: class AffiliateProgram { private static int accountOpenBonus = 5; } Declare and initialize a static variable Licensed to Mark Watson 111 Static and final keywords But what happens if you need to use a calculated value or initialize the value of accountOpenBonus based on the outcome of a condition: class AffiliateProgram { private static int accountOpenBonus; static { if (/* file XYZ exists */) accountOpenBonus = 5; else accountOpenBonus = 15; } } Conditional assignment of variable accountOpenBonus Again, you might argue that you can move the preceding conditional execution to a static method and use it to initialize variable accountOpenBonus, without using the static initializer block: class AffiliateProgram { private static int accountOpenBonus = initAccountOpenBonus(); private static int initAccountOpenBonus() { if (/* file XYZ exists */) return 5; else return 15; } Conditional assignment of variable accountOpenBonus using static method } What happens if method initAccountOpenBonus() throws a checked exception, say, FileNotFoundException? In this case, you must use a static initializer block to assign the returned value from initAccountOpenBonus() to variable accountOpenBonus. As you know, if a method throws a checked exception, its use should either be enclosed within a try block or the method that uses it should declare the exception to be thrown. In this case, neither is possible; the declaration of the variable accountOpenBonus can’t be enclosed within a try block because this statement doesn’t exist within a method or code block. Here’s the relevant code: Won’t compile; can’t declare and initialize variable using method that throws checked exception import java.io.*; class AffiliateProgram { private static int accountOpenBonus = initAccountOpenBonus(); private static int initAccountOpenBonus() throws FileNotFoundException { //relevant code } } Licensed to Mark Watson 112 CHAPTER 2 Advanced class design And here’s the way out: Static method that static initializer block Static class AffiliateProgram { throws checked variable private static int accountOpenBonus; exception private static int initAccountOpenBonus() throws FileNotFoundException{ //..relevant code } static { try { try block to catch accountOpenBonus = initAccountOpenBonus(); FileNotFoundException } thrown by catch (FileNotFoundException e) { initAccountOpenBonus() //.. relevant code } } } Another reason for the existence of a static initializer block is to add values (static or dynamic) to collection objects that have already been initialized. Here’s an example: class AddValuesToStaticVariables { static private String[] dataStores = new String[5]; static { dataStores[0] = "us.ny"; dataStores[1] = "jp.tk"; dataStores[2] = "gr.br"; //..code that assigns dynamic value to dataStores[] } } String array dataStores is initialized. Add explicit values to dataStores. Pull values from the database and add to String array dataStores. The static initializer blocks can be tricky and cumbersome to work with when it comes to debugging them. On the exam, beware of code that defines multiple initializer blocks. If a class defines multiple initializer blocks, they execute in the order of their appearance in a class. Let’s examine output of code that defines multiple initializer blocks: class StaticInitBlocks { static int staticVar = 10; static { System.out.println("First"); ++staticVar; } static { System.out.println("Second"); ++staticVar; } static void modifyStaticVar() { ++staticVar; } Licensed to Mark Watson Static and final keywords 113 public StaticInitBlocks() { System.out.println("Constructor:" + staticVar); } public static void main(String args[]) { new StaticInitBlocks(); modifyStaticVar(); new StaticInitBlocks(); } } Code in a static initializer block executes when a class is loaded in memory by JVM— before creation of its instances. The output of the preceding code is as follows: First Second Constructor:12 Constructor:13 Can the static and instance initializer blocks access the static or instance variables of a class, like other methods? Let me modify the preceding code and use it for the next “Twist in the Tale” exercise. Twist in the Tale 2.2 Following is modified code for class DemoMultipleStaticBlocks. Answer the question before you execute it on your system. Which answer correctly shows its output? class DemoMultipleStaticBlocks { static { ++staticVar; } static int staticVar ; static { ++staticVar; } public DemoMultipleStaticBlocks() { System.out.println("Constructor:" + staticVar); } public static void main(String args[]) { new DemoMultipleStaticBlocks(); } } a b c d e Constructor: 2 Constructor: 1 Constructor: 0 Compilation error Runtime exception Licensed to Mark Watson 114 CHAPTER 2 Advanced class design On the exam, beware of code that defines multiple initializer blocks. If a class defines multiple initializer blocks, they execute in the order of their appearance in a class. EXAM TIP Watch out for another combination on the exam: initialization of a static class variable and its manipulation in a static block. What do you think is the order of execution in the following code? Will the following example code print 1 or 11? Declare static variable rate and assign 0 to it. public class AssignManipulateStaticVariable { static { rate = 10; } static int rate = 0; static { ++rate; } public AssignManipulateStaticVariable() { System.out.println(rate); } public static void main(String args[]) { new AssignManipulateStaticVariable(); } First static initializer block to assign 10 to rate Second static initializer block to increment rate by 1 Prints “1” } For the preceding code, the compiler rearranges the code to execute. It declares the static variable age and then picks up the code from all the static initializer blocks and assignment of age and combines them in a single static initializer block, in the order of their occurrence, as follows: static int rate; static { rate = 10; rate = 0; ++rate; } The preceding code explains why AssignManipulateStaticVariable prints 1 and not 11. STATIC CLASSES AND INTERFACES Let’s look at other types of static entities: static classes and interfaces. These are also referred to as nested classes, static nested classes, static interfaces, and static nested interfaces. You can’t prefix the definition of a top-level class or an interface with the keyword static. A top-level class or interface is one that isn’t defined within another class or interface. The following code fails to compile: static class Person {} static interface MyInterface {} Licensed to Mark Watson 115 Static and final keywords But you can define a class and an interface as a static member of another class. The following code is valid: Static nested class class Person { static class Address {} static interface MyInterface {} } Static nested interface As you know, the static variables and methods of a class are accessible without the existence of any of its objects. Similarly, you can access a static class without an object of its outer class. You’ll learn all about the other details of the static classes in section 2.3.2 . 2.2.2 Nonaccess modifier—final The decision to apply the nonaccess modifier final to a class, interface, variable, or method is an important class design decision. To start, should you define your class as a final class? Yes, if you don’t want it to be subclassed. Should you define your method as a final method? Yes, if you don’t want any of its subclasses to override it. Do you want to define a variable as a final variable? Yes, if after the variable is initialized, you don’t want it to be reassigned another value. Knowing these details will enable you to make the right decisions—when, why, where, and how to apply the nonaccess modifier final and when not to. Apart from testing you on how to use the modifier final in code, the exam will also query you on the implications of its use on the design or behavior of code. Let’s start with final variables. FINAL VARIABLES The final variables can be initialized only once. You can tag all types of variables— static variables, instance variables, local variables, and method parameters—with the nonaccess modifier final. Because of the differences in how these variable types are initialized, they exhibit different behavior. Let’s start with defining a static variable as a final variable: class TestFinal { static final int staticFinal = 10; } A final static class variable can be initialized with its declaration, or by using a static initializer block, which is guaranteed to execute only once for a class. Because a static method can be called multiple times, it can’t define code to initialize a final (static) variable: class TestFinal { static final int staticFinal2 = 12345; Static final variable initialized with its declaration static final int staticFinal; static { staticFinal = 1234; } Static initializer block to initialize static variable Static final variable not initialized Licensed to Mark Watson 116 CHAPTER 2 Advanced class design static void setStaticFinal(int value) { staticFinal = value; } Won’t compile; static method can execute multiple times and so it can’t include initialization of final variable. } Because the constructor of a class executes on creation of every instance of the class, you can’t initialize a final static variable in the constructor. The following code won’t compile: class FinalStatic { static final int finalVar; Final static variable can’t be initialized in constructor of a class FinalStatic() { finalVar = 10; } } Similarly, though you can initialize a final instance variable in the class’s constructor or its instance initializer block, you can’t initialize it in an instance method. Instance methods can execute more than once: Instance final variable initialized with its declaration class InstanceFinalVariables { final int finalVar2 = 710; Instance final variable not initialized final int finalVar; InstanceFinalVariables() { finalVar = 10; } void setValue(int a) { finalVar = a; } Class’s constructor initializes instance final variable Won’t compile; a method may execute multiple times and so can’t include code to initialize a final variable. } If a static or instance variable is marked final, it must be initialized, or the code won’t compile. EXAM TIP Interestingly, you can survive code with an uninitialized final local variable, if you don’t use it: class MyClass { void setValue(int a) { final int finalLocalVar1; finalLocalVar1 = 20; final int finalLocalVar2; } } Final local variable declared and initialized on separate lines Uninitialized final local variable; compiles successfully Licensed to Mark Watson 117 Static and final keywords In the preceding code, if you try to use the uninitialized final local variable finalLocalVar2, your code won’t compile. Modified code is as follows: class MyClass { void setValue(int a) { final int finalLocalVar1; finalLocalVar1 = 20; Won’t compile when you try to use an uninitialized local variable. final int finalLocalVar2; System.out.println(finalLocalVar2); } } Method parameters are initialized when the method is invoked. If a method marks its method parameter(s) as final, the method body can’t reassign a value to it, as follows: class MyClass { void setValue(final int finalMethodParam) { finalMethodParam = 10; } } Final method parameter Won’t compile; value can’t be assigned to final method parameter. There’s a difference between final primitive variables and final object reference variables. The final primitive variables can’t change, but the object referred to by final object reference variables can be changed. Only the final reference itself can’t be changed: Final method class MyClass { parameter void addCondition(final StringBuilder query) { query.append("WHERE id > 500"); query = new StringBuilder("SELECT name FROM emp"); } } Won’t compile; can’t reassign Can modify object referred to by final reference variable query. another object to final reference variable query. CONDITIONAL ASSIGNMENT OF FINAL VARIABLES What happens when you initialize a final variable within an if-else construct, switch statement, or for, do-while, or while loop? In this case, code that assigns a value to the final variable might not execute. If the Java compiler is doubtful about the initialization of your final variable, the code won’t compile. For example, the constructor of MyClass assigns a value to its final instance variable finalVar by using an if statement, as shown in the following code listing. Licensed to Mark Watson 118 CHAPTER 2 Advanced class design Listing 2.1 Conditional assignment of final instance variable in class’s constructor class MyClass { final int finalVar; MyClass(double a, double b) { if (a > b) finalVar = 20; else if (b >= a) finalVar = 30; } } b c Assigns 20 to finalVar if a > b Assigns 30 to finalVar if b >= a Class MyClass fails compilation with the following compilation error message: variable finalVar might not have been initialized The code at B assigns a value to finalVar if the condition a > b evaluates to true. The code at c assigns a value to finalVar if condition b >= a evaluates to true. The compiler has its doubts about being able to execute (and thus initialize) in all conditions. So, the Java compiler will consider initialization of a final variable complete only if the initialization code will execute in all conditions. Adding an else branch results in successful code compilation: class MyClass { final int finalVar; MyClass(double a, double b) { if (a>b) finalVar = 20; else finalVar = 30; } } b c Assigns 20 to finalVar if a > b Assigns 30 to finalVar otherwise In the preceding code, B initializes finalVar to 30 if the condition a > b evaluates to true. Otherwise, it initializes finalVar to 30 at c. Let’s modify the code in listing 2.1 so it uses constant literal values instead of variables, in if conditions: class MyClass { final int finalVar; MyClass(double a, double b) { if (1>2) finalVar = 10; else if (100>10) finalVar = 20; } } Assigns 10 to finalVar if 1 > 2 b Assigns 20 to finalVar if 100 > 10 The preceding code compiles successfully, because with the constant values, the compiler can determine that code at B will execute, initializing a value to the final variable for sure. Licensed to Mark Watson Static and final keywords 119 Let’s modify the code again, so it continues to use the variables in the if conditions. In listing 2.1, the Java compiler complained that variable finalVar might not have been initialized. So let’s explicitly assign a value to variable finalVar, before the start of the if statement, as follows: class MyClass { final int finalVar; MyClass(double a, double b) { finalVar = 100; if (a>b) finalVar = 20; else if (b>=a) finalVar = 30; } } b c Explicit assignment to final variable finalVar Conditional assignment to final variable finalVar The code at B initializes finalVar, and the code at c tries to assign a value to it, conditionally. Because a final variable can’t be reassigned a value, the preceding code fails compilation with the following compilation error message: variable finalVar might already have been assigned finalVar = 20; ^ On the exam, look out for multiple initializations of a final variable. Code snippets that try to reinitialize a final variable won’t compile. EXAM TIP The simplest way to initialize a final variable is to do so with its declaration. If not initialized with its declaration, a static final variable can be initialized in the class’s static initializer block. An instance final variable can be initialized in its constructor or the instance initializer block. A local final variable can be assigned a value in the method in which it’s defined. A final method parameter can’t be reassigned a value within the method. It’s time for you to attempt the next “Twist in the Tale” exercise, which tests you on understanding assignment of a base class’s final instance variable from the derived class. Twist in the Tale 2.3 Let’s modify the code used in the preceding examples so class MyClass does not initialize its final instance variable finalVar. This variable is initialized in its derived class, MyDerivedClass, as follows: abstract class MyClass { public final int finalVar; } class MyDerivedClass extends MyClass { MyDerivedClass() { super(); finalVar = 1000; } } Licensed to Mark Watson 120 CHAPTER 2 Advanced class design Your task is to first think about the possible output of the following code before you compile it on your system: class Test { {System.out.println(new MyDerivedClass().finalVar);} public static void main(String args[]) { new Test(); } } FINAL METHODS The final methods defined in a base class can’t be overridden by its derived classes. The final methods are used to prevent a derived class from overriding the implementation of a base class’s method. Can you think of any scenario where you’d need this? Picture this: the base class of all the Java classes, java.lang.Object, defines multiple final methods—wait, notify, getClass. Methods wait() and notify() are used in threading and synchronization. If the derived classes were allowed to override these methods, how do you think Java would implement threading and synchronization? If a derived class tries to override a final method from its base class, it won’t compile, as follows: class Base { final void finalMethod() {} } class Derived extends Base { void finalMethod() {} } Final method in base class Won’t compile; final method in base class can’t be overridden. The preceding code fails to compile, with the following compilation error message: finalMethod() in Derived cannot override finalMethod() in Base final void finalMethod() {} ^ overridden method is final 1 error As you know, you can override only what is inherited by a derived class. The following code compiles successfully, even though the derived class seems to override a final method from its base class: class Base { private final void finalMethod() {} } class Derived extends Base { final void finalMethod() {} } Private methods aren’t inherited by derived classes. Compiles successfully Licensed to Mark Watson 121 Static and final keywords The base class’s private methods aren’t inherited by a derived class. In the previous code, method finalMethod() is defined as a private method in class Base. So it doesn’t matter whether it’s marked as a final method. Method finalMethod() defined in class Derived doesn’t override the base class’s method finalMethod(). Class Derived defines a new method, finalMethod(). The private methods of a base class aren’t inherited by its derived classes. A method using the same signature in the derived class isn’t an overridding method, but a new method. EXAM TIP FINAL CLASSES You can prevent a class from being extended by marking it as a final class. But why would you do so? A class marked as a final class can’t be derived by any other class. For example, class String, which defines an immutable sequence of characters, is defined as a final class. It’s a core class, which is used in a lot of Java API classes and userdefined classes. What happens, say, if a developer extends class String and modifies its equals() method to return a value true for all method parameter values passed to it? Because we can’t extend the final class String, let’s create a class MyString and override its equals() method to return true without comparing any values: class MyString { String name; MyString (String name) {this.name = name;} public boolean equals(Object o) { return true; } } Many classes from the Java API, like HashMap and ArrayList, rely heavily on the correct implementation of equals() for searching, deleting, and retrieving objects. Imagine the effect it would have if you try to use objects of class MyString in an ArrayList and retrieve a matching value: class UseMyStringInCollectionClasses { public static void main(String args[]) { ArrayList list = new ArrayList<>(); MyString myStrEast = new MyString("East"); MyString myStrWest = new MyString("West"); list.add(myStrEast); System.out.println(list.contains(myStrWest)); } } Creates ArrayList—list Add only one element to list—myStrEast Prints “true”—list can find myStrWest, which was never added to it. Surprisingly, the preceding code prints true even though list doesn’t contain a matching MyString object. This is because method contains90 in ArrayList uses the equals() (overridden) method of the objects it holds. If you can’t get all of this explanation, don’t worry. Collection classes are covered in detail in chapter 4. Imagine the Licensed to Mark Watson 122 CHAPTER 2 Advanced class design havoc that objects of an extended String class can cause, if class String wasn’t defined as a final class, was allowed to be extended, and its methods overridden. You can mark a class as a final class by prefixing its definition with the keyword final: final class FinalClass { //.. this need not be detailed here } Class is marked final by adding final to its definition. You can’t reverse the position of the keywords final and class: class final ClassBeforeFinalWontCompile {} Won’t compile; position of keywords class and final can’t be interchanged. The original intent of defining an abstract class was to extend it to create more meaningful and concrete classes. Because a final class can’t be extended, you can’t define a class both as final and abstract: abstract final class FinalAbstractClassDontExist {} Won’t compile; a class can’t be defined both as final and abstract. If you try to extend a final class, your class won’t compile: final class Base {} class Derived extends Base {} Final class Won’t compile; can’t extend a final base class. Look out for trick questions on the exam that extend final classes from the Java API, like class String and the wrapper classes Byte, Short, Integer, Long, Float, Double, Boolean, and Character. When you don’t look at the source code of the base class and see that it’s marked final, it’s easy to overlook that the classes that extend it won’t compile. Though the authors of this exam claim not to include trick questions, they also state that they expect the candidates to know “their stuff.” EXAM TIP The enumerated types share some characteristics of the final keyword. Enumerated types enable you to define a new type, but with a predefined set of objects. Let’s see how in the next section. 2.3 Enumerated types [2.5] Use enumerated types Think of the courses offered by a university or maybe even the roles within an organization: each defines a finite and predefined set of objects. These finite and predefined Licensed to Mark Watson 123 Enumerated types sets of objects can be defined as enumerated types, or enums. An enum defines a new custom data type (like interfaces and classes). Users are allowed to use only existing enum objects; they can’t create new enum objects. Type safety was the main reason for introducing enumerated types in Java version 5.0, discussed further in the following section. 2.3.1 Understanding the need for and creating an enum Let’s assume that you have been assigned the task of creating a gaming application that can be played at exactly three levels: beginner, intermediate, and expert. How would you restrict your variable to be assigned only these three values? You can accomplish this by creating an enum. An enum enables you to create a type, which has a fixed set of constants. Following is an example of the enum Level, which defines three programming levels: enum Level { BEGINNER, INTERMEDIATE, EXPERT } The enum values are constant values. An enum lets you define a new type, the way classes and interfaces enable you to define your own types. The preceding line of code creates a new type, Level, which defines the constants BEGINNER, INTERMEDIATE, and EXPERT of type Level. (Syntactically, you can use any case for defining these constant values, but following Oracle’s recommendation of using uppercase letters for constant values will save you a lot of headaches.) These constants are also static members and are accessible by using the name of the enum in which they’re defined. You can assign a gaming level, defined by the enum Level for a game. Let’s define a class, Game, which defines an instance variable, gameLevel, of type Level, as follows: class Game { Level gameLevel; } Variable of type Level Class GameApp defines a field game of type Game and initializes it as follows: class GameApp { Game game = null; public void startGame () { game = new Game(); game.gameLevel = Level.BEGINNER; } Assigns constant BEGINNER } The class GameApp demonstrates the real benefit of all this enum business. Because the variable gameLevel (defined in class Game) is of type Level, you can assign only one of the constants defined in the enum Level—that is, Level.BEGINNER, Level.INTERMEDIATE, or Level.EXPERT. Let’s look into the finer details of enums, as discussed in the next section. Licensed to Mark Watson 124 2.3.2 CHAPTER 2 Advanced class design Adding implicit code to an enum When you create an enum, Java adds implicit code and modifiers to its members. These details will help you explain the behavior of enum constants, together with how to access and use them. Let’s work with the enum Level created in the previous section (2.3.1) and decompile its Level.class file, using a decompiler (like JD): enum Level { BEGINNER, INTERMEDIATE, EXPERT } A decompiler converts Java byte code (.class) to a Java source file (.java). The newly created Java source file will include any implicit code that was added during the compilation process. Listing 2.2 shows decompiled enum Level (to make the code easier to understand, I’ve added some comments): Listing 2.2 Decompiled enum Level b final class Level { public static public static public static extends Enum enum is implicitly declared final. c final Level BEGINNER; final Level INTERMEDIATE; final Level EXPERT; enum constants are implicitly public, static, and final. private static final Level $VALUES[]; static { BEGINNER = new Level("BEGINNER", 0); INTERMEDIATE = new Level("INTERMEDIATE", 1); EXPERT = new Level("EXPERT", 2); $VALUES = (new Level[] { BEGINNER, INTERMEDIATE, EXPERT }); } public static Level[] values() { return (Level[])$VALUES.clone(); } f public static Level valueOf(String s) { return (Level)Enum.valueOf(Level, s); } private Level(String s, int i) { super(s, i); } h d e Array to store reference to all enum constants Creation of enum constants occurs in static initializer block Method values return an array of all enum constants. g Method valueOf() parses a String value and returns corresponding enum constant Private constructor } In the decompiled code, at B you can notice that an enum is implicitly defined as a final entity. At c you can notice that all enum constants are implicitly declared as public, final, and static variables. The code at d defines an array to store a Licensed to Mark Watson Enumerated types 125 reference to all enum constants. The variables are declared at c and d. They are initialized in a static initializer block at e. Method values() returns an array of all enum constants at f and valueOf() returns an enum constant for a corresponding String value at g. The code at h defines a private constructor. If the enum constants are themselves created in a static initializer block, when does a static initializer block in an enum execute? See for yourself in the next “Twist in the Tale” exercise. Twist in the Tale 2.4 Let’s add some code to the enum Level so it defines a constructor and a static initializer block. Examine the code and determine the correct options that follow. enum Level { BEGINNER; static{ System.out.println("static init block"); } Level(){ System.out.println("constructor"); } public static void main(String... args){ System.out.println(Level.BEGINNER); } } a constructor static init block BEGINNER b static init block constructor BEGINNER c constructor static init block beginner d static init block constructor beginner In listing 2.2 you’ll notice that all enum constants of BEGINNER, INTERMEDIATE, and EXPERT are created in the order they were defined and assigned an ordinal: 0, 1, and 2. Are enum constants created in this manner? Let’s check it out in the next section. 2.3.3 Extending java.lang.Enum All enums in Java extend the abstract class java.lang.Enum, defined in the Java API. As always, it’s interesting to peek at the source code from the Java API, to understand why some pieces of code behave in a particular way. Let’s look at the (partial) code of class java.lang.Enum, which will help you get the hang of how the enum constants are created, their order, and their default names. Please note that the comments Licensed to Mark Watson 126 CHAPTER 2 Advanced class design aren‘t part of the code from class java.lang.Enum. These comments have been added to clarify the code for you. Listing 2.3 Partial code listing of class java.lang.Enum public abstract class Enum > implements Comparable , Serializable { private final String name; private final int ordinal; protected Enum(String name, int ordinal) { this.name = name; this.ordinal = ordinal; } public String toString() { return name; } public final String name() { return name; } //.. rest of the code Name of the enum constant Position of enum constant Name and position of enum constant is saved on its creation Default implementation of toString() returns name of enum constant Method name() is marked final and can’t be overridden; returns enum constant’s name. } The class Enum defines only one constructor with String and int parameters to specify its name and ordinal (order). Every enum constant is implicitly assigned an order on its creation. Let’s refer back to the example of enum Level as defined in listing 2.2. The enum constant values BEGINNER, INTERMEDIATE, and EXPERT are created within the enum Level, in its static initializer block (refer to code listing 2.1), as follows: public static final level BEGINNER = new Level ("BEGINNER", 0); public static final level INTERMEDIATE = new Level ("INTERMEDIATE", 1); public static final level EXPERT = new Level ("EXPERT", 2); EXAM TIP Watch out for exam questions that use methods like Collections.sort() from the Collections API to sort enum constants. The default order of enum constants is their order of definition. The enum constants aren’t sorted alphabetically. Now, examine the following code: public class TestEnum { public static void main(String args[]) { System.out.println(Level.BEGINNER.name()); System.out.println(Level.BEGINNER); } } Prints “BEGINNER” Licensed to Mark Watson Also prints “BEGINNER” by calling method toString() 127 Enumerated types Note both methods—toString() and name() defined in java.lang.Enum—return the value of the instance variable name (revisit code listing 2.3—class java.lang.Enum defines an instance variable name). Because method name() is a final method, you can’t override it. But you can override method toString() to return any description that you want. For an enum constant BEGINNER in enum Level, calling System.out.println(Level.BEGINNER) returns the name of the enum constant—that is, BEGINNER. You can override toString() in an enum to EXAM TIP modify this default return value. Because a class can extend from only one base class, an attempt to make your enum extend any other class will fail. The following code won’t compile: class Person {} enum Level extends Person { BEGINNER, INTERMEDIATE, EXPERT } Won’t compile But you can make your enum implement any number of interfaces. A class can extend only one base class but can implement multiple interfaces. The following code compiles successfully: interface MyInterface {} enum Level implements MyInterface { BEGINNER, INTERMEDIATE, EXPERT } You can’t explicitly make a class extend java.lang.Enum: class MyClass extends java.lang.Enum {} Will compile Won’t compile An enum implicitly extends java.lang.Enum, so it can’t extend any other class. But a class can’t explicitly extend java.lang.Enum. EXAM TIP 2.3.4 Adding variables, constructors, and methods to your enum You can add variables, constructors, and methods to an enum. You can also override the nonfinal methods from the java.lang.Enum class. Following is an example: enum IceCream { VANILLA, STRAWBERRY, WALNUT, CHOCOLATE; b c private String color; public String getColor() { return color; } public void setColor(String val) { color = val; } d enum constants Instance variable in enum IceCream Method getColor() e Method setColor() Licensed to Mark Watson 128 CHAPTER 2 Advanced class design public String toString() { return "MyColor:"+ color; } f Override method toString() } The code at B defines a list of enum constants: VANILLA, STRAWBERRY, WALNUT, and CHOCOLATE in enum IceCream. Note that this constant list must be the first in the enum definition and should be followed by a semicolon. A semicolon is optional if you don’t add methods and variables to your enum. The code at c defines an instance variable color in enum IceCream. The code at d and e adds methods getColor() and setColor() to enum IceCream. The code at f overrides the public toString() method inherited from class java.lang.Enum. The enum constant list must be the first in the enum definition and should be followed by a semicolon. A semicolon is optional if you don’t add methods and variables to your enum. EXAM TIP You can call the methods defined in the preceding example, as follows: public class UseIceCream { public static void main(String[] args) { IceCream.VANILLA.setColor("white"); System.out.println(IceCream.VANILLA.getColor()); System.out.println(IceCream.VANILLA); } } b c d The output of this code is as follows: white MyColor:white Are you thinking that the code at B is invalid because enum values are constant values? Note that this code is absolutely valid. VANILLA is a type of enum IceCream, and you can call methods that are available to it. The code at c calls the method getColor(), and the code at d calls method toString(), which was overridden in enum IceCream. You can also define constructors in your enum and override methods that apply only to particular enum constants, as follows in listing 2.4 (modifications in bold): Listing 2.4 enum IceCream with custom constructor and constant specific class body enum IceCream { VANILLA("white"), STRAWBERRY("pink"), Licensed to Mark Watson 129 Enumerated types This method can’t be executed. c WALNUT("brown") { public String toString() { return "WALNUT is Brown in color"; } public String flavor() { return "great!"; } }, CHOCOLATE("dark brown"); private String color; IceCream(String color) { this.color = color; } public String toString() { return "MyColor:" + color; } d b Methods defined between { and } are available only to enum constant WALNUT. Constructor that accepts string } The code at B, known as a constant specific class body, defines overridding methods for a particular enum constant, WALNUT. The code at d defines a constructor for enum IceCream, but it can be used only within an enum. A constructor in an enum can be defined only with default or private access; public and protected access levels aren’t allowed. An enum can’t define a constructor with public or protected access level. EXAM TIP In the preceding code, it might be strange to note that though you can define a method flavor() at c, you can’t call it, as follows: public class UseIceCream { Prints public static void main(String[] args) { “MyColor:white” System.out.println(IceCream.VANILLA); System.out.println(IceCream.WALNUT); Prints “WALNUT is //System.out.println(IceCream.WALNUT.flavor()); Brown in color” } } Won’t compile This behavior can be attributed to WALNUT creating an anonymous class and overriding the methods of enum IceCream. But it’s still referenced by a variable of type IceCream, which doesn’t define the method flavor. If this leaves you guessing about what all this stuff with anonymous classes is, you can go grab a glass of anonymous inner classes in section 2.4.4. Let’s see how class IceCream’s constant WALNUT returns a custom value for its toString() method, that it overrides in its constant specific class body. In the following example, class IceCreamParlor uses method values() to access all enum constants and outputs their values: class IceCreamParlor { public static void main(String args[]) { Licensed to Mark Watson 130 CHAPTER 2 Advanced class design for (IceCream ic : IceCream.values()) System.out.println(ic); } } Method values() returns an array of all enum constants. The output of the preceding code is MyColor:white MyColor:pink WALNUT is Brown in color MyColor:dark brown In the preceding output, notice how the String representation of WALNUT differs from the other enum constants. An enum constant can define a constant specific class body and use it to override existing methods or define new variables and methods. EXAM TIP 2.3.5 Where can you define an enum? You can define an enum as a top-level enum, or as a member of a class or an interface. Until now, you worked with a top-level enum. The following code shows you how to define an enum as a member of another class or interface: class MyClass { enum Level { BEGINNER, INTERMEDIATE, EXPERT } } interface MyInterface { enum Level { BEGINNER, INTERMEDIATE, EXPERT } } enum as a member of other class enum as a member of an interface But you can’t define an enum local as a method. For example, the following code won’t compile: class MyClass { void aMethod() { enum Level { BEGINNER, INTERMEDIATE, EXPERT } } } At the end of this section on enums, let’s revisit the important rules that you should remember for the exam. Rules to remember about enums ■ ■ An enum can define a main method. This means that you can define an enum as an executable Java application. The enum constant list must be defined as the first item in an enum, before the declaration or definition of methods and variables. Licensed to Mark Watson 131 Enumerated types (continued) ■ The enum constant list might not be followed by a semicolon, if the enum doesn’t define any methods or variables. ■ When an enum constant overrides an enum method, the enum constant creates an anonymous class, which extends the enum. ■ An enum constant can define a constant specific class body and use it to override existing methods or define new variables and methods. ■ An enum implicitly extends java.lang.Enum, so it can’t extend any other class. But a class can’t explicitly extend java.lang.Enum. An enum can implement interface(s). ■ An enum can never be instantiated using the keyword new. ■ You can define multiple constructors in your enums. ■ An enum can’t define a constructor with public or protected access level. ■ An enum can define an abstract method. Just ensure to override it for all your enum constants. ■ The enum method values() returns a list of all the enum constants. ■ An enum can be defined as a top-level enum, or as a member or another class or interface. It can’t be defined local to a method. When you’re consuming a lot of information, missing the small and simple details is easy. Let’s check whether you remember and can spot some basic information about enums in the next “Twist in the Tale” exercise. Twist in the Tale 2.5 Let’s modify the code used in enum IceCream in this section. Examine the code and determine the correct options that follow. public enum IceCreamTwist { VANILLA("white"), STRAWBERRY("pink"), WALNUT("brown"), CHOCOLATE("dark brown"); String color; IceCreamTwist(String color) { this.color = color; } public static void main(String[] args) { System.out.println(VANILLA); System.out.println(CHOCOLATE); } //line1 //line2 } a b Compilation error: Can’t run an enum as a standalone application. Compilation error at (#1) and (#2): Can’t access VANILLA and CHOCOLATE in a static main method. Licensed to Mark Watson 132 CHAPTER 2 Advanced class design c No errors. Output is VANILLA CHOCOLATE d No errors. Output is white dark brown An enum defines a new type with limitations. Similarly, nested and inner classes define a new type with constraints on their use. Defined within another class, nested and inner classes are characterized with a different set of behavior that sets them apart from the top-level classes. Let’s uncover these details in the next section. 2.4 Static nested and inner classes [2.4] Create top-level and nested classes A nested class is a class defined within another class. Nested classes that are declared as static are referred to as static nested classes. Nested classes that aren’t declared as static are referred to as inner classes. Like a regular top-level class, an inner or static nested class can define variables and methods. You can also define inner classes within methods and without a name. Figure 2.5 shows the types of inner classes, distinguished by their placement within the top-level class and whether they are defined as and with static members. Before we dive into a detailed discussion of all the flavors of the inner classes, table 2.2 provides a quick definition of the types of inner classes. Table 2.2 Flavors of inner classes and their definitions Type of inner class Description Static or static nested class Is a static member of its enclosing class and can access all the static variables and members of its outer class Inner or member class Is an instance member of its enclosing class. It can access all the instance and static members of its outer class, including private members. Method local inner class Is defined within a method. Local inner classes are local to a method. They can access all the members of a class, including its private members, but they can be accessed only within the method in which they’re defined. Anonymous inner class Is a local class without a name For the exam, you’ll need to know why inner classes and static nested classes are important in the design of an application, their advantages and disadvantages, and how to create and use them. Let’s start with a discussion of the advantages of inner Licensed to Mark Watson 133 Static nested and inner classes Class Outer { class Inner{ static class StaticNested{ } } Outer class Inner class Local inner class Anonymous inner class Static nested class void foo(){ class LocalInner{} } static void foo(){ class LocalInner{} } Object foo(){ return new Object{}{ public String toString(){ return "anonymous"; } }; } static Object foo(){ } return new Object{}{ public String toString(){ return "anonymous"; } }; } Nonstatic Static Figure 2.5 An outer class showing all types of inner classes that it can define: inner class, static nested class, local inner class, and anonymous inner class classes, followed by a detailed discussion of all these classes. At the end of this section, we’ll discuss their disadvantages. 2.4.1 Advantages of inner classes Inner classes offer multiple advantages. To start, they help you objectify the functionality of a class, within it. For example, you might define a class Tree, which defines operations to add objects, remove objects, and sort them based on a condition. Instead of defining methods and variables to sort them within the class Tree, you could encapsulate sorting functionality within another class TreeSort. Because the class TreeSort would always work with Tree and might not be needed outside the class Tree, TreeSort can be defined as an inner class within class Tree. Another example for using inner classes is as parameter containers. Instead of using long method signatures, inner classes are often used to keep method signatures compact by passing reference parameters of inner classes instead of a long list of individual parameters. Just as you can organize your top-level classes by using packages, you can further organize your classes by using inner classes. Inner classes might not be accessible to all other classes and packages. Licensed to Mark Watson 134 CHAPTER 2 Advanced class design Inner classes also offer a neat way to define callback methods. For example, consider a user-interface-intensive GUI application, which defines multiple controls (buttons, keys, and screen) to accept a user’s input. These user controls should register listeners, which are classes that define methods that are called back, when a user control receives an input. Instead of defining a single class to handle all callback methods for multiple user controls, you can use inner classes to define callback methods for individual user controls. Let’s start with the simplest type of inner class: a static nested class. 2.4.2 Static nested class (also called static inner class) A static nested class is a static class that’s defined (nested) within another class. It’s referred to as a nested class and not an inner class because it isn’t associated with any instance of its outer class. You’d usually create a static nested class to encapsulate partial functionality of your main class, whose instance can exist without the instance of its outer class. It can be accessed like any other static member of a class, by using the class name of the outer class. A static nested class is initialized when it’s loaded with its outer class in memory. Figure 2.6 shows a static nested class. Class Outer { class Inner{ static class StaticNested{ } } Outer class Inner class In this section: Static nested class Local inner class Anonymous inner class Static nested class void foo(){ class LocalInner{} static void foo(){ class LocalInner{} } } Object foo(){ return new Object{}{ public String toString(){ return "anonymous"; static Object foo(){ return new Object{}{ public String toString(){ return "anonymous"; } } }; }; } } } Nonstatic Static Figure 2.6 A static nested class within an outer class Licensed to Mark Watson Static nested and inner classes 135 In the following (simplified) example, class DBConnection defines a static nested class, DBConnectionCache, which creates and stores database connections with default connection values. When requested a database connection, class DBConnection checks if a default connection for the specified database exists. If yes, it returns the default connection; otherwise it creates and returns a new connection. class DBConnection { public DBConnection (String username, String pwd, String URL) { // code to establish a Database connection } public DBConnection OracleConnection (String username, String pwd, String URL) { DBConnection conn = DBConnectionCache.getDefaultOracleConnection(); if (conn != null) { return conn; } else { //establish and return new DBconnection using method parameters } } /* * Oversimplified version of a static nested class which uses default * values to establish DB connections and store them in a static array */ static class DBConnectionCache { static DBConnection connections[]; static { connections = new DBConnection[3]; connections[0] = new DBConnection (/*arguments to establish a connection to an ORACLE DB*/); connections[1] = new DBConnection (/*arguments to establish a connection to a MySQL DB*/); } static DBConnection getDefaultOracleConnection() { return connections[0]; } static DBConnection getDefaultMySQLConnection() { return connections[1]; } } } EXAM TIP In the preceding example, access to nested class DBConnectionCache can be restricted by using an appropriate access modifier with its definition. In the next section, you’ll work with one of the most important points to be tested on the exam—how to instantiate static nested classes. Licensed to Mark Watson 136 CHAPTER 2 Advanced class design Let’s code class StaticNested as shown in figure 2.6: class Outer { static int outerStatic = 10; int outerInstance = 20; static class StaticNested { static int innerStatic = 10; int innerInstance = 20; } } A static nested class isn’t usually referred to as an inner class, because it isn’t associated with an object of the outer class. NOTE When you create a static nested class, it’s compiled as a separate class file. The .class file for a static nested file includes the name of its outer class. On compiling the code shown in the preceding example, the compiler generates two .class files, Outer.class and Outer$StaticNested.class. As with a regular top-level class, a static nested class is a type and you can instantiate it. Multiple separate instances of a static nested class can be created. Each instance of the static nested class can have a different value for its instance variables. Let’s instantiate the StaticNested class from the preceding example code: class Outer { static int outerStatic = 10; int outerInstance = 20; static class StaticNested { static int innerStatic = 10; int innerInstance = 20; } public static void main(String args[]) { StaticNested nested1 = new StaticNested(); Outer.StaticNested nested2 = new Outer.StaticNested(); Modify only the value of innerInstance for nested1. nested1.innerStatic = 99; nested1.innerInstance = 999; When static nested class is instantiated within its outer class, it doesn’t need to be prefixed with its outer class name (though it can). Modify the value of innerStatic for all instances of StaticNested. System.out.println(nested1.innerStatic + ":" + nested1.innerInstance); System.out.println(nested2.innerStatic + ":" + nested2.innerInstance); Prints “99:999” Prints “99:20” } } When a static nested class is instantiated outside its outer class, you must prefix it with its outer class name: When static nested class is instantiated outside its outer class, it must be prefixed with its outer class name class AnotherClass { Outer.StaticNested nested1 = new Outer.StaticNested(); StaticNested nested2 = new StaticNested(); } Licensed to Mark Watson Won’t compile 137 Static nested and inner classes StaticNested one = new StaticNested(); Outer.StaticNested two = new Outer.StaticNested(); StaticNested three = new Outer.new StaticNested(); StaticNested four = new Outer().new StaticNested(); StaticNested five = Outer.new StaticNested(); Figure 2.7 Correct and incorrect instantiation of a static nested class For the exam, it’s important to remember the syntax of instantiating a static nested class: the count of operator new and its placement. It uses the new operator once, just before the name of the static nested class. Figure 2.7 highlights correct and incorrect instantiation code snippets. Another point that you must remember when instantiating a static nested class is when to prefix the name of a static nested class with its outer class. Figure 2.8 shows Hi Hi StaticNested ! Outer.StaticNested ! Hi Shreya! Hi Paul! Within class Outer Method Shreya() Method Paul() Class StaticNested Hi Hi StaticNested ! Outer.StaticNested ! Hi Paul! Who is that girl calling? Outside class Outer Method Shreya() Method Paul() Class StaticNested Figure 2.8 An interesting way to remember that you must prefix the name of the static inner class with its outer class when referring to it outside its outer class. Licensed to Mark Watson 138 CHAPTER 2 Advanced class design an interesting way to remember that you must prefix the name of the static inner class with its outer class when you’re referring to it outside its outer class. For the rest of the cases you might, but it isn’t mandatory, prefix the name of the static nested class with its outer class. In figure 2.8 when method Shreya doesn’t prefix StaticNested with its outer class, outside the class Outer, StaticNested doesn’t seem to recognize the call. ACCESSING MEMBERS OF A STATIC NESTED CLASS To access the static members of a static nested class, you need not create an object of this class. You need an object of a static nested class to access its instance members. Here’s an example: Object of StaticNested class required to access its instance members class Outer1 { public static void main(String args[]) { System.out.println(new Outer.StaticNested().innerInstance); System.out.println(Outer.StaticNested.innerStatic); } } Object of StaticNested class not required to access its static members On the exam, you might be asked whether you can instantiate a static nested class, how to instantiate it, and whether it can define instance or static members, or both. NOTE ACCESS LEVELS OF A STATIC NESTED CLASS A static nested class can be defined using all access levels: private, default access, protected, and public. The accessibility of the static nested class depends on its access modifier. For example, a private static nested class can’t be accessed outside its outer class. The access of a static nested class also depends on the accessibility of its outer class. If the outer class is defined with the default access, an inner nested class with public access won’t make it accessible outside the package in which its outer class is defined. MEMBERS OF OUTER CLASS ACCESSIBLE TO STATIC NESTED CLASS A static nested class can access only the static members of its outer class. An example follows. class Outer { static int outerStatic = 10; int outerInstance = 20; static class StaticNested { static int innerStatic = outerInstance; int innerInstance = outerInstance;; } Can’t access instance variables from a static nested class } Licensed to Mark Watson 139 Static nested and inner classes Rules to remember about static nested classes ■ ■ ■ ■ ■ ■ 2.4.3 To create an object of a static nested class, you need to prefix its name with the name of its outer class (necessary only if you’re outside the outer class). A static nested class can define both static and nonstatic members. You need not create an object of a static nested class to access its static members. They can be accessed the way static members of a regular class are accessed. You should create an object of a static nested class to access its nonstatic members, by using the operator new. A static nested class can be defined using any access modifier. A static nested class can define constructor(s). Inner class (also called member class) The definition of an inner class is enclosed within another class, also referred to as an outer class. An inner class is an instance member of its outer class. An instance of an inner class shares a special bond with its outer class and can’t exist without its instance. Figure 2.9 illustrates the placement of an inner class within an outer class. Class Outer { class Inner{ static class StaticNested{ } } Outer class Inner class In this section: Inner class Local inner class Anonymous inner class Static nested class void foo(){ class LocalInner{} } static void foo(){ class LocalInner{} } Object foo(){ return new Object{}{ public String toString(){ return "anonymous"; static Object foo(){ return new Object{}{ public String toString(){ return "anonymous"; } } }; }; } } } Nonstatic Figure 2.9 Placement of an inner class within an outer class Licensed to Mark Watson Static 140 CHAPTER 2 Advanced class design You’d usually create an inner class to encapsulate partial functionality of your main class such that the existence of the inner class instance isn’t possible without its outer class instance. This is in contrast to a nested static class, which can be used without an instance of its outer class. For example, the following code defines a class Tree and an inner class TreeSort. Tree defines operations to add, remove, and sort objects based on a condition. Instead of defining methods and variables to sort the tree elements within class Tree, it encapsulates sorting functionality within class TreeSort. Class TreeSort would always work with Tree and might not be needed without class Tree: class Node { Object value; Instances of Node Node left, right; used to store Tree } elements class Tree { Tree() {} Node rootNode; void addElement(Object value) { //.. code // } void removeElement(Object value) { //.. code // } void sortTree(boolean ascending) { new TreeSort(ascending).sort(); Defining sorting code } in a separate inner class makes class Tree class TreeSort{ simpler and cleaner. boolean ascendingSortOrder = true; TreeSort(boolean order) { ascendingSortOrder = order; } void sort() { // outer class’s rootNode and sort tree values // sorting code can be complex } } } Figure 2.10 illustrates the bare-bones inner class Inner, defined within another class, Outer, and how the compiler generates separate class files for the outer and inner classes. Throughout this section, I refer to the concept of outer and inner classes as outer class and inner class. I refer to names of the outer class and inner class by using code font. You can create an outer class and inner class using any names. The names of these classes are chosen as Outer and Inner so it’s easy for you to recognize them. NOTE Licensed to Mark Watson 141 Static nested and inner classes Let me assign separate space to inner class In class Outer { Java compiler class Inner{} Outer.class } Outer$Inner.class Out Separate class files for outer and inner classes Figure 2.10 The compiler generates separate class files for an outer class and inner class. The name of the inner class is prefixed with the name of the outer class and a $ sign. CHARACTERISTICS OF INNER CLASSES Because an inner class is a member of its outer class, an inner class can be defined using any of the four access levels: public, protected, default access, and private. Like a regular top-level class, an inner class can also define constructors, variables, and methods. But an inner class can’t define nonfinal static variables or methods, as shown in figure 2.11. An inner class… class Outer { protected class Inner{ Inner(){} public String publicInner = "Inner"; private int privateInner = 20; //static int staticInner = 10; //static void staticMethod(){} } Can be defined using any access modifier Can define constructors } Can define instance variables and methods Can’t define static methods and nonfinal static variables Figure 2.11 Characteristics of an inner class: it can be defined using any access modifier, can define constructors, and can define instance variables and methods. An inner class can define static members variables but not static methods. Licensed to Mark Watson 142 CHAPTER 2 Advanced class design CREATION OF AN INNER CLASS Whenever you instantiate an inner class, remember that an instance of an inner class can’t exist without an instance of the outer class in which it’s defined. Let’s look at creating an inner class: ■ ■ ■ ■ Within an outer class, as an instance member Within a method of an outer class Within a static method of an outer class Outside the outer class First, a definition of a bare-bones outer class and inner class follows: class Outer { class Inner {} } Bare-bones inner class Bare-bones outer class Class Outer can instantiate inner class Inner as its instance member (additions in bold), as follows: class Outer { Inner objectInner = new Inner(); class Inner {} } Creation of object of class Inner in class Outer, as its instance member In the previous code, like all instance variables, objectInner can access an instance of its outer class and its members, Outer. Similarly, an instance of an inner class created within an instance method of an outer class can access the instance of its outer class. So, you can instantiate class Inner within an instance method of class Outer, as follows (additions in bold): class Outer { Inner in = new Inner(); class Inner {} void aMethod () { Inner objectInner = new Inner(); } } EXAM TIP Instantiation of class Inner in class Outer within its method You must have an outer class instance to create an inner class instance. Now, let’s try to instantiate class Inner within a static method of class Outer (additions in bold): class Outer { class Inner {} static void staticMethod() { Inner in = new Inner(); } } b Won’t compile Licensed to Mark Watson 143 Static nested and inner classes The code at B doesn’t compile because in method staticMethod() there’s no outer class instance to tie the inner class instance to, which is required for creation of its inner class Inner. But it’s possible to instantiate class Outer in the method staticMethod(). When you have an Outer instance, you can instantiate Inner: class Outer { class Inner {} static void staticMethod () { Outer outObj = new Outer(); Inner innerObj = outObj.new Inner(); } } b Instance of Outer can be created in method staticMethod() c Instance of Inner is created by calling operator new on Outer instance The code at B creates outObj, an Outer instance in the static method staticMethod(). outObj is used to create an instance of class Inner at c because you need an outer class instance to create an inner class instance. It’s interesting to note that the operator new is called on outObj to create the innerObj instance. Have you invoked the operator new on an object earlier? The operator new is always used to instantiate a class. But to instantiate an inner class by using an instance of an outer class, you should invoke the operator new on the outer class’s instance. Following is another way of creating the instance innerObj, using a single line of code: class Outer { class Inner {} static void staticMethod () { Inner innerObj = new Outer().new Inner(); } } b Single line of code creates inner class object in outer class’s static method The code at B may look bizarre, because it contains two occurrences of the operator new. The first occurrence of this operator is used to create an instance of Outer. The second occurrence is used to create an instance of class Inner. If another class wants to create an instance of class Inner, it needs an instance of class Outer. If it doesn’t have one, it should first create one, just like with method staticMethod() in the previous code snippet: class Foo { Inner inner; Foo () { Outer outer = new Outer(); inner = outer.new Inner(); } } Won’t compile Licensed to Mark Watson 144 CHAPTER 2 Advanced class design What makes the preceding code fail compilation? Inner isn’t a top-level class, so its variable type should include the name of its outer class, Outer, so class Foo can find this class. The following code compiles successfully and creates an Inner instance: class Foo { Outer.Inner inner; Foo () { Outer outer = new Outer(); inner = outer.new Inner(); } } Outside its outer class, the type of inner class should include the name of its outer class. Similarly, a static method of class Foo can instantiate Inner, as follows: class Foo { public static void main(String args[]) { Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); } } The accessibility of an inner class outside its outer class depends on the access modifier used to define the inner class. For example, an inner class with default access can’t be accessed by classes in different packages than the outer class. EXAM TIP WHAT CAN AN INNER CLASS ACCESS? An inner class is a part of its outer class. Therefore an inner class can access all variables and methods of an outer class, including its private members and the ones that it inherits from its base classes. An inner class can also define members with the same name as its outer class, as shown in figure 2.12. class Outer private String privateOuter = "Outer"; private int sameName = 20; class Inner{ String publicInner = privateOuter; private variable of class Outer accessible in class Inner int sameName = Outer.this.sameName; } } Object of class Outer can be accessed using Outer.this in class Inner Figure 2.12 An inner class can access all the members of its outer class, including its private members. Outer class members with the same name as inner class members can be accessed using Outer.this, where Outer is the name of the outer class. Licensed to Mark Watson Static nested and inner classes this Class Outer 145 Refers to object of class Outer Outer.this this Class Inner Refers to object of class Inner Figure 2.13 An inner class uses this to refer to its own object and .this to refer to its outer class’s object. An object uses the reference this to refer to its own object. An inner class can use the reference this to refer to its own object, and the name of its outer class followed by .this to refer to the object of its outer class, as shown in figure 2.13. CAN AN INNER CLASS COEXIST WITH ONLY ITS OUTER CLASS? Yes, an inner class can exist only with an object of its outer class. When a compiler compiles an inner class, it seems to insert code in the inner class, which defines an instance variable of its outer class, initialized using its constructor, as illustrated in figure 2.14. class Outer { class Inner{} Code added before byte code generation } 1 private final Outer this$0; Inner (Outer outer){ this$0 = outer; } In 2 Out Java compiler } 3 4 class Outer { class Inner{ In Out Outer.class Outer$Inner.class Figure 2.14 Java instantiates an inner class by passing it an outer class instance. Licensed to Mark Watson 146 CHAPTER 2 Advanced class design Rules to remember about inner classes ■ ■ ■ ■ ■ ■ ■ ■ You can create an object of the inner class within an outer class or outside an outer class. When an inner class is created outside its outer class, its type name should include the name of its outer class, followed by a dot (.) and then the name of the inner class. To create an inner class with a static method of an outer class, or outside an outer class, call the operator new on the object of the outer class to instantiate the inner class. An inner class can’t define static methods. It can define final static variables but nonfinal static variables aren’t allowed. Members of the inner class can refer to all variables and methods of the outer class. An inner class can be defined with all access modifiers. An inner class can define constructors. An inner class can define variables and methods with any access level. It’s time to attempt a quick exercise on inner classes in the following “Twist in the Tale” exercise. Twist in the Tale 2.6 Apart from modifying the code used in an earlier example, I have also modified the class names for this exercise. Your task is to examine the following code and determine the correct answer option. class Flower { String color = "red"; Petal[] petals; private class Petal { public Petal() {System.out.println(color);} String color = "purple"; // line 1 static final int count = 3; // line 2 } Flower() { petals = new Petal[2]; // line 3 } public static void main(String args[]) { new Flower(); } } Licensed to Mark Watson Static nested and inner classes a b c d e f g h 147 Code prints red twice. Code prints purple twice. Code prints red three times. Code prints purple three times. Code prints nothing. Code fails compilation due to code at (#1). Code fails compilation due to code at (#2). Code fails compilation due to code at (#3). Anonymous classes are another type of inner class. As their title suggests, they don’t have a name. In the next section, you’ll see why we need unnamed inner classes, and when and how they are created. 2.4.4 Anonymous inner classes As the name implies, an anonymous inner class isn’t defined using an explicit name. An anonymous inner class is created when you combine instance creation with inheriting a class or implementing an interface. Anonymous classes come in handy when you wish to override methods for only a particular instance. They save you from defining new classes. The anonymous class might override none, few, or all methods of the inherited class. It must implement all methods of an implemented interface. The newly created object can be assigned to any type of variable—static variable, instance variable, local variable, method parameter, or returned from a method. Let’s start with an example of an anonymous inner class that extends a class. ANONYMOUS INNER CLASS THAT EXTENDS A CLASS Let’s start with a class Pen: class Pen{ public void write() { System.out.println("Pen-write"); } } This is how a class, say, Lecture, would usually instantiate Pen: class Lecture { Pen pen = new Pen(); } Licensed to Mark Watson 148 CHAPTER 2 Advanced class design Let’s replace this usual object instantiation by overriding method write, while instantiating Pen. To override method write() for this particular instance, we insert a class definition between () and ; (() and ; are in bold): b Create an anonymous class that extends class Lecture { class Pen. Pen pen = new Pen() { public void write() { System.out.println("Writing with a pen"); } } End class ; definition for End of creation of object } anonymous class. referred to by variable pen, c d Begin class definition for anonymous class. Override method write() for instance referred to by pen. e f marked by semicolon. The preceding code creates an anonymous class, which extends class Pen. The object reference pen refers to an object of this anonymous class. The code at B creates an object. Note that this line of code isn’t followed by a semicolon. Instead, it’s followed by an opening brace at c, which starts the definition of the anonymous class that extends Pen. The code at d overrides method write() from the base class Pen. The closing brace at e marks the end of the definition of the anonymous class. The code at f defines the semicolon, which is used to mark the end of object creation, which started at B. I’ve deliberately placed the semicolon on a separate line so you can clearly identify the start and end of the anonymous class. It’s usual to place this semicolon after the closing brace, used to mark the end of the anonymous class. You can create an anonymous class even if you don’t override any methods of class Pen: class Lecture { static Pen pen = new Pen(){}; Create an anonymous class, which extends Pen but doesn’t override its methods. Prints a value similar to Pen@1034bb5; public static void main(String args[]) { new Pen() returns an object of Pen. System.out.println(new Pen()); System.out.println(pen); Prints a value similar to Lecture$1@15f5897; } pen refers to an instance of anonymous class that extends Pen. } Similarly, you can pass an anonymous class instance to a method parameter. Now let’s see an example of method notes() in class Lecture, which accepts a method parameter of type Pen: class Pen{ public void write() { System.out.println("Pen-write"); } } Licensed to Mark Watson Static nested and inner classes class Lecture { public void notes(Pen pen) { pen.write(); } } 149 Method notes() accepts parameter of type Pen. Here’s how another class—say, Student—calls notes() from class Lecture, subclassing Pen, and passing the object to it: class Student { Call notes() by passing void attendLecture() { it newly baked object of Lecture lecture = new Lecture(); anonymous subclass of Pen. lecture.notes(new Pen() { public void write() { System.out.println("Okay! I am writing"); } } ); } } The preceding code can seem to be more complex than the previous example. To understand it better, let’s build this code, line by line. In class Student, you call notes() on object reference lecture: class Student { void attendLecture() { Lecture lecture = new Lecture(); lecture.notes(/* need to pass Pen object */); } } In the next step, I’ll replace the comment in the preceding code with new Pen(){}, so I’m ready to subclass Pen (additions in bold): class Student { void attendLecture() { Lecture lecture = new Lecture(); lecture.notes(new Pen(){}); } } I’ll insert the definition of overridden method write() within the curly brace {} of the Pen anonymous inner class declaration, included in the method parameter to notes() (additions in bold): class Student { void attendLecture() { Lecture lecture = new Lecture(); lecture.notes(new Pen(){public void write() { System.out.println("Okay! I am writing"); }}); } } Licensed to Mark Watson 150 CHAPTER 2 Advanced class design Let’s indent the code, to improve the readability: class Student { void attendLecture() { Lecture lecture = new Lecture(); lecture.notes(new Pen(){ public void write() { System.out.println("Okay! I am writing"); } }); } } You can use an anonymous inner class to return a value from a method: class Outer{ Object foo() { return new Object() { public String toString() { return "anonymous"; } }; } } Create an anonymous class that subclasses class Object. Override method toString() from class Object. ANONYMOUS INNER CLASS THAT IMPLEMENTS AN INTERFACE Until now, you should have read that you can’t instantiate interfaces; you can’t use the keyword new with an interface. Think again. Examine the following code, in which the class BirdSanctuary instantiates the interface Flyable by using the keyword new: interface Flyable{ void fly(); } Use new to class BirdSanctuary { instantiate interface. Flyable bird = new Flyable(){ public void fly() { System.out.println("Flying high in the sky"); } }; } Don’t worry; you’ve been reading correctly that you can’t use the operator new with an interface. The catch in the preceding code is that bird refers to an object of an anonymous inner class, which implements the interface Flyable. The anonymous class used to instantiate an interface in the preceding code saved you from creating a class beforehand, which implemented the interface Flyable. EXAM TIP An anonymous inner class can extend at most one class or implement one interface. Unlike other classes, an anonymous class can neither implement multiple interfaces, nor extend a class and implement an interface together. Licensed to Mark Watson 151 Static nested and inner classes HOW TO ACCESS ADDITIONAL MEMBERS IN ANONYMOUS CLASSES By using an anonymous class, you can override the methods from its base class or implement the methods of an interface. You can also define new methods and variables in an anonymous class (in bold): interface Flyable{ void fly(); } class BirdSanctuary { Flyable bird = new Flyable(){ public void fly() { System.out.println("Flying high in the sky"); } public void hungry(){ System.out.println("eat"); } }; } You can’t call the additional member, method hungry(), using the reference variable bird. Why? The type of the reference variable bird is Flyable. So the variable bird can access only the members defined in interface Flyable. The variable bird can’t access additional methods and variables that are defined in anonymous classes that implement it. ANONYMOUS CLASS DEFINED WITHIN A METHOD When an anonymous inner class is defined within a method, it can access only the final variables of the method in which it’s defined. This is to prevent reassignment of the variable values by the inner class. Examine the following example. class Pizza{ Object margarita() { String ingredient = "Cheese"; return new Pizza() { public String toString() { System.out.println(ingredient); return "margarita"; } }; } } b Won’t compile The code at B will compile if ingredient is modified to be defined as a final local variable. The last type of inner class on this exam is a method local inner class, which can be created within methods and code blocks like initializer blocks, conditional constructs, or loops. I’ll discuss these in the next section. Licensed to Mark Watson 152 CHAPTER 2 Advanced class design class Outer { void outerMethod(){ class Inner{} In } } Separate class files Java compiler Out Outer.class Outer$1Inner.class Figure 2.15 Compiler generates separate class files for an outer class and method local inner class. The name of the method local inner class is prefixed with the name Outer class, a $ sign, and an integer. 2.4.5 Method local inner classes The method local inner classes are defined within static or instance methods of a class. Though these classes can also be defined within code blocks, they are typically created within methods. So their discussion will be limited to their creation in methods. Figure 2.15 shows the definition of a bare-bones method local inner class, Inner, defined within method outerMethod() of class Outer. The Java compiler generates separate class files for the classes Outer and Inner. Because a class can define method local inner classes with the same name in separate methods, the Java compiler adds a number to the name of the compiled file for the local inner classes. A class can define multiple method local inner classes, with the same class name, in separate methods, as follows: class Outer { void outerMethod () { class Inner { } } static void outerMethod2 () { class Inner { } } } Class Inner defined in method outerMethod() Class Inner defined in method outerMethod2() For the preceding code, the Java compiler will generate three class files: Outer.class, Outer$1Inner.class, and Outer$2Inner.class. CHARACTERISTICS OF METHOD LOCAL INNER CLASSES Recall that none of the variables within a method can be defined using any explicit modifier (public, protected, private). Similarly, method local inner classes can’t be defined using any explicit access modifier. But a method local inner class can Licensed to Mark Watson 153 Static nested and inner classes define its own constructors, variables, and methods by using any of the four access levels: class Outer { Can’t be defined using an private int privateOuter = 10; explicit access modifier void outerMethod () { class Inner { protected Inner() {} Can define its constructs, variables, public int publicInner = 100; and methods using any access level int privateInner = privateOuter; } Can access all members, } including private members, } of its outer class But a method local inner class can’t define static variables or static methods. CREATION OF A LOCAL INNER CLASS A method local inner class can be created only within the method in which it’s defined. Also, its object creation can’t appear before the declaration of the local inner class, as shown in the following code: class Outer { void outerMethod () { //Inner in1 = new Inner(); class Inner {} Inner in2 = new Inner(); } } Won’t compile Will compile WHAT CAN A METHOD LOCAL INNER CLASS ACCESS? A method local inner class can access all variables and methods of its outer class, including its private members and the ones that it inherits from its base classes. A method local inner class can also define members with the same name as its outer class. In this case, the members of the outer class can be referred to by using the name of the outer class followed by the implicit reference this. Class Inner can access members of class Outer by using Outer.this, as shown in the following code: class Outer { private int privateOuter = 10; void outerMethod () { class Inner { protected Inner() {} public int publicInner = 100; int privateInner = Outer.this.privateOuter; } } } 2.4.6 Local inner class can access all members of its outer class, including private members. Disadvantages of inner classes Using inner classes is an advanced concept, and it can be difficult for inexperienced programmers to identify, implement, and maintain them. Licensed to Mark Watson 154 CHAPTER 2 Advanced class design On translation to byte code, inner classes can be accessed by classes in the same package. Because inner classes can access the private members of their outer class, they could break the designed encapsulation. You need to be careful when you create the inner and static nested classes. 2.5 Summary This chapter covers abstract classes, static and final keywords, enumerated types, and nested and inner classes. The choice of identifying abstract classes isn’t straightforward. This chapter showed you simple examples so you’re well aware of their need, importance, advantages, and shortcomings. Application of the static and final nonaccess modifiers are important design decisions. You should know about the Java entities that can use these modifiers, together with how they change the default behavior of the entities. Incorrect design decisions can make an application inefficient and difficult to extend or maintain. This chapter covered enums that are used to create a new type with a finite and predefined set of objects. The definition of an enum can be as simple as including only the name of enum constants, or as complex as including variables, constructors, and methods. The exam is sure to test you on the finer details of enums, all covered in this chapter. Static nested classes, inner classes, anonymous inner classes, and method local inner classes were also covered. An inner class shares an intimate relation with its outer class. Inner classes help you objectify the functionality of a class. Identification of an inner class is also an important design decision. It can help you further organize your code and allow limited access to your inner classes. But an overdose of the inner and nested classes can make your application difficult to work with and manage. REVIEW NOTES This section lists the main points covered in this chapter. Abstract classes ■ ■ ■ ■ ■ ■ An abstract class is defined by using the keyword abstract. It defines variables to store the state of an object. It may define abstract and nonabstract methods. An abstract class must not necessarily define abstract methods. But if it defines even one abstract method, it must be marked as an abstract class. An abstract class can’t be instantiated. An abstract method doesn’t have any implementation. It represents a behavior that’s required by all derived classes of an abstract class. Because the base class doesn’t have enough details to implement an abstract method, the derived classes are left to implement it in their own specific manner. An abstract class can’t be instantiated. An abstract class forces all its nonabstract-derived classes to implement the incomplete functionality in their own unique manner. Licensed to Mark Watson Review notes ■ ■ ■ ■ ■ ■ 155 A base class should be defined as an abstract class so it can implement the available details but still prevent itself from being instantiated. An abstract class can be extended by both abstract and concrete classes. If an abstract class is extended by another abstract class, the derived abstract class might not implement the abstract methods of its base class. If an abstract class is extended by a concrete class, the derived class must implement all the abstract methods of its base class, or it won’t compile. A derived class must call its superclass’s constructor (implicitly or explicitly), irrespective of whether the superclass or derived class is an abstract class or concrete class. An abstract class can’t define abstract static methods. Because static methods belong to a class and not to an object, they aren’t inherited. A method that can’t be inherited can’t be implemented. Hence this combination is invalid. Efficient use of an abstract class lies in the identification of an abstract class in your application design so you can define common code for your objects and leave the ones that are more specific, by defining them as abstract. You can enforce the derived classes to implement these abstract methods. Nonaccess modifier—static ■ ■ ■ ■ ■ ■ ■ Static members (fields and methods) are common to all instances of a class, and aren’t unique to any instance of a class. Static members exist independently of any instances of a class, and may be accessed even when no instances of the class have been created. Static members are also known as class fields or class methods because they are said to belong to their class, and not to any instance of that class. A static variable and method can be accessed using the name of an object reference variable or the name of a class. A static method and variable can’t access nonstatic variables and methods of a class. But the reverse works: nonstatic variables and methods can access static variables and methods. Static classes and interfaces are a type of nested classes and interfaces. You can’t prefix the definition of a top-level class or an interface with the keyword static. A top-level class or interface is one that isn’t defined within another class or interface. Nonaccess modifier—final ■ ■ You can’t reinitialize a final variable defined in any scope—class, instance, local, or method parameter. An instance final variable can be initialized either with its declaration in the initializer block or in the class’s constructor. Licensed to Mark Watson 156 CHAPTER 2 Advanced class design ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ A static final variable can be initialized either with its declaration or in the class’s static initializer block. You can’t initialize a final instance variable in an instance method because it can’t be guaranteed to execute only once. Such a method won’t compile. You can’t initialize a final static variable in a static method because it can’t be guaranteed to execute only once. Such a method won’t compile. If you don’t initialize a final local variable in a method, the compiler won’t complain, as long as you don’t use it. If you try to access the value of a final local variable before assigning a value to it, the code won’t compile. The Java compiler considers initialization of a final variable complete only if the initialization code will execute in all conditions. If the Java compiler can’t be sure of execution of code that assigns a value to your final variable, it will complain (code won’t compile) that you haven’t initialized a final variable. If an if construct uses constant values, the Java compiler can predetermine whether the then or else blocks will execute. In this case, it can predetermine whether these blocks of code will execute to initialize a final variable. A final instance variable defined in a base class can’t be initialized in the derived class. If you try to do so, your code won’t compile. Final methods defined in a base class can’t be overridden by its derived classes. Final methods are used to prevent a derived class from overriding the implementation of a base class’s method. Private final methods in a base class aren’t inherited by derived classes. A method defined using the same method signature in a derived class isn’t an overridden method, but a new method. A final class can’t be extended by any other class. A class is defined as final so that it can’t be extended by any other class. This prevents objects of derived classes from being passed on to reference variables of their base classes. An interface can’t be defined as final because an interface is abstract, by default. A Java entity can’t be defined both as final and abstract. Enumerated types ■ ■ ■ ■ ■ ■ Enumerated types are also called enums. An enum enables you to create a type, which has a fixed set of constants. An enum can never be instantiated using the keyword new. Unlike a class, which is defined using the keyword class, an enumerated type is defined using the keyword enum, and can define multiple variables and methods. If you define a variable of an enum type, it can be assigned constant values only from that enum. All enums extend the abstract class java.lang.Enum, defined in the Java API. Licensed to Mark Watson Review notes ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ 157 Because a class can extend from only one base class, an attempt to make your enum extend any other class will fail its compilation. The enum constants are implicit static members. An enum can implement any interface, but its constants should implement the relevant interface methods. An enum can define an abstract method. Just ensure that you override it for all your enum constants. You can add instance variables, class variables, instance methods, and class methods to your enums. An enum can’t use instance variables in the overridden methods for a particular enum constant. You can override nonfinal methods from class java.lang.Enum, for individual (or all) enum constants. Your enums can also define constructors, which can be called from within the enum. You can define multiple constructors in your enums. Enum constants can define new methods, but these methods can’t be called on the enum constant. You can define an enum as a top-level enum or within another class or interface. You can’t define an enum local to a method. An enum can define a main method. Static nested classes ■ ■ ■ ■ ■ ■ ■ ■ This class isn’t associated with any object of its outer class. Nested within its outer class, it’s accessed like any other static member of a class—by using the class name of the outer class. A static nested class is accessible outside the class in which it’s defined by using names of both the outer class and inner class. You can define both static and nonstatic members in a static nested class. A static nested class can define constructors. To access the static members of a static nested class, you need not create an object of this class. You need an object to access the instance members of this class. The accessibility of the nested static class depends on its access modifier. For example, a private static nested class can’t be accessed outside its class. A static nested class can access only the static members of its outer class. Similarly, the outer class can access only the static members of its nested inner class. An attempt to access instance members on either side will fail compilation unless it’s accessed through an instance of the outer or static nested class. All access levels can be used with this class—public, protected, default, and private. Licensed to Mark Watson 158 CHAPTER 2 Advanced class design Inner classes ■ ■ ■ ■ ■ ■ ■ ■ ■ An inner class is an instance member of its outer class. An object of an inner class shares a special bond with its outer class and can’t exist without its instance. An inner class can be defined using any of the four access levels—public, protected, default, and private. Members of an inner class can refer to all variables and methods of an outer class. An inner class can define constructors. An inner class can define variables and methods with any access. An inner class can’t define static methods and nonfinal static variables. You can create an object of an inner class within an outer class or outside an outer class. Outside the outer class an inner class is instantiated using Outer.Inner inner = new Outer().new Inner(); Anonymous inner classes ■ ■ ■ ■ ■ An anonymous inner class is created when you combine object instance creation with inheriting a class or implementing an interface. An anonymous inner class might override none, few, or all methods of the inherited class. An anonymous inner class must implement all methods of the implemented interface. An instance of an anonymous class can be assigned to any type of variable (static variable, instance variable, or local variable) or method parameter, or be returned from a method. The following line creates an anonymous inner class that extends Object and assigns it to a reference variable of type Object: Object obj = new Object(){}; ■ The following line calls a method, say aMethod(), passing to it an instance of an anonymous class that implements Runnable: aMethod(new Runnable() { public void run() {} }); ■ ■ When an anonymous inner class is defined within a method, it can access only the final variables of the method in which it’s defined. This is to prevent reassignment of the variable values by the inner class. Though you can define variables and methods in an anonymous inner class, they can’t be accessed using the reference variable of the base class or interface, which is used to refer to the anonymous class instance. Licensed to Mark Watson Sample exam questions 159 Method local inner classes ■ ■ ■ ■ ■ ■ ■ Method local inner classes are defined within a static or instance method of a class. A class can define multiple method local inner classes, with the same class name, but in separate methods. Method local inner classes can’t be defined using any explicit access modifier. A method local inner class can define its own constructors, variables, and methods by using any of the four access levels—public, protected, default, and private. A method local inner class can be created only within the method in which it’s defined. Also, its object creation can’t appear before its declaration. A method local inner class can access all variables and methods of its outer class, including its private members and the ones that it inherits from its base classes. It can only access the final local variables of the method in which it’s defined. A method local inner class can define members with the same name as its outer class. In this case, the members of the outer class can be referred to by using Outer.this. SAMPLE EXAM QUESTIONS Q 2-1. Select the correct statement(s) based on the following code: enum Keywords { ASSERT(1.4), DO, IF, WHILE; double version = 1.0; // line1 // line2 // line3 Keywords() { this.version = 1.0; } // constructor 1 // constructor 1 // constructor 1 Keywords(double version) { this.version = version; } // constructor 2 // constructor 2 // constructor 2 public static void main(String args[]) { Keywords[] keywords = Keywords.values(); for (Keywords val:keywords) System.out.println(val); } } a b c d e The enum keywords won’t compile due to code at (#1). The enum keywords won’t compile due to code at either (#2) or (#3). If you swap the complete code at (#1) and (#2) with code at (#3), enum keywords will compile successfully. The enum keywords will fail to compile due to the declaration of multiple constructors. None of the above Licensed to Mark Watson 160 CHAPTER 2 Advanced class design Q 2-2. Consider the following definition of class Foo: abstract class Foo { abstract void run(); } Which of the classes correctly subclass Foo? (Choose all that apply.) a class Me extends Foo { void run() {/* ... */} } b abstract class You extends Foo { void run() {/* ... */} } c interface Run { void run(); } class Her extends Foo implements Run { void run() {/* ... */} } d abstract class His extends Foo { String run() {/* ... */} } Q 2-3. Which lines of code, when inserted at //INSERT CODE HERE, will print the following: BASKETBALL:CRICKET:TENNIS:SWIMMING: enum Sports { TENNIS, CRICKET, BASKETBALL, SWIMMING; public static void main(String args[]) { // INSERT CODE HERE } } d for (Sports val:Sports.values()) System.out.print(val+":"); for (Sports val:Sports.orderedValues()) System.out.print(val+":"); for (Sports val:Sports.naturalValues()) System.out.print(val+":"); for (Sports val:Sports.ascendingValues()) System.out.print(val+":"); e None of the above a b c Q 2-4. Given that classes Outer and Test are defined in separate packages and source code files, which code options, when inserted independently at //INSERT CODE HERE, will instantiate class Inner in class Test? (Choose all that apply.) // Source code-Outer.java package ejava.ocp; public class Outer { public static class Inner{} } Licensed to Mark Watson Sample exam questions 161 // Source code-Test.java package ejava.exams; import static ejava.ocp.Outer.Inner; class Test { //INSERT CODE HERE } a b c d Inner inner = new Inner(); Outer.Inner inner = new Outer.Inner(); Outer.Inner inner = new Inner(); Outer.Inner inner = Outer.new Inner(); Q 2-5. Given the following definition of classes Outer and Inner, select options that can be inserted individually at //INSERT CODE HERE. (Choose all that apply.) class Outer { void aMethod() { class Inner { // INSERT CODE HERE } } } a b c d e f g h protected Inner() {} final static String name = "eJava"; static int ctr = 10; private final void Inner() {} Outer outer = new Outer(); Inner inner = new Inner(); static void print() {} static final void print() {} Q 2-6. Given the following definition of enum Size, select the commented line number(s) in class MyClass, where you can insert the enum definition individually. (Choose all that apply.) enum Size {SMALL, MEDIUM, LARGE} class MyClass { // line1 void aMethod() { //line2 } class Inner { //line3 } static class StaticNested{ //line4 } } Licensed to Mark Watson 162 CHAPTER 2 Advanced class design a b c d The code at (#1) The code at (#2) The code at (#3) The code at (#4) Q 2-7. Given the following code, which option, when inserted at /*INSERT CODE HERE*/, will instantiate an anonymous class referred to by the variable floatable? interface Floatable { void floating(); } class AdventureCamp { Floatable floatable = /*INSERT CODE HERE*/ } f new new new new new new g None of the above a b c d e Floatable(); Floatable(){}; Floatable() { public void floating() {}}; Floatable() public void floating() {}; Floatable(public void floating() ) {}}; Floatable() { void floating() {}}; Q 2-8. What is the output of the following code? (Choose all that apply.) interface Admissible {} // line1 class University { static void admit(Admissible adm) { System.out.println("admission complete"); } public static void main(String args[]) { admit(new Admissible(){}); // line2 } } a b c d The class prints admission complete. The class doesn’t display any output. The class fails to compile. University will print admission complete if code at (#2) is changed to the following: admit(new Admissible()); e f Class University instantiates an anonymous inner class. If Admissible is defined as a class, as follows, the result of the preceding code will remain the same: class Admissible {} Licensed to Mark Watson 163 Sample exam questions Q 2-9. Which of the following statements are correct? (Choose all that apply.) a b c d e f An abstract class must define variables to store the state of its object. An abstract class might define concrete methods. An abstract class might not define abstract methods. An abstract class constructor might be called by its derived class. An abstract class can extend another nonabstract class. An abstract class can’t define static final abstract methods. Q 2-10. Which of the classes, when inserted at //INSERT CODE HERE, will create an instance of class Inner? (Choose all that apply.) class Outer { class Inner {} } class Test { //INSERT CODE HERE } a b c d e f g h Outer.Inner Outer.Inner Outer.Inner Outer.Inner Outer.Inner Outer outer Inner inner Outer outer Outer.Inner Outer outer Inner inner inner inner inner inner inner = new = new = new inner = new = new = new Outer.Inner(); = Outer().new Inner(); = Outer.new Inner(); = new Outer().new Inner(); = new Inner(); Outer(); Outer.Inner(); Outer(); = outer.new Inner(); Outer(); outer.Inner(); Q 2-11. Select the incorrect options. (Choose all that apply.). a b c d e An anonymous inner class always extends a class, implicitly or explicitly. An anonymous inner class might not always implement an interface. An anonymous inner class is a direct subclass of class java.lang.Object. You can make an anonymous inner class do both—explicitly extend a userdefined class and an interface. An anonymous inner class can implement multiple user-defined interfaces. Q 2-12. Select the correct options for the classes Satellite and Moon: abstract class Satellite{ static { ctr = (int)Math.random(); } // line1 Licensed to Mark Watson 164 CHAPTER 2 Advanced class design static final int ctr; } class Moon extends Satellite{ public static void main(String args[]) { System.out.println(Moon.ctr); } } a b c d // line2 // line3 Code at only (#1) fails compilation. Code at either (#1) or (#2) fails compilation. Code at (#3) fails compilation. Code compiles and executes successfully. Q 2-13. What is the output of the following code? enum BasicColor { RED; static { System.out.println("Static init"); } { System.out.println("Init block"); } BasicColor(){ System.out.println("Constructor"); } public static void main(String args[]) { BasicColor red = BasicColor.RED; } } a Init block Constructor Static init b Static init Init block Constructor c Static init Constructor Init block d Constructor Init block Static init Q 2-14. What is the output of the following code? enum Browser { FIREFOX("firefox"), IE("ie"){public String toString() {return "Internet Browser";}}, NETSCAPE("netscape"); Browser(String name){} Licensed to Mark Watson Sample exam questions 165 public static void main(String args[]) { for (Browser browser:Browser.values()) System.out.println(browser); } } a FIREFOX Internet Browser NETSCAPE b FIREFOX INTERNET BROWSER NETSCAPE c FIREFOX IE NETSCAPE d firefox ie netscape Q 2-15. What is the output of the following code? class Base { static { System.out.print("STATIC:"); } { System.out.print("INIT:"); } } class MyClass extends Base { static { System.out.print("static-der:"); } { System.out.print("init-der:"); } public static void main(String args[]) { new MyClass(); } } a b c d STATIC:INIT:static-der:init-der: INIT:STATIC:init-der:static-der: STATIC:static-der:INIT:init-der: static-der:init-der:STATIC:INIT: Q 2-16. Select the correct statements. (Choose all that apply.). a b An abstract class can’t define static final variables. The abstract methods defined in an abstract base class must be implemented by all its derived classes. Licensed to Mark Watson 166 CHAPTER 2 Advanced class design c d e An abstract class enforces all its concrete derived classes to implement its abstract behavior. An abstract class might not define static methods. The initialization of the final variables defined in an abstract base class can be deferred to its derived classes. ANSWERS TO SAMPLE EXAM QUESTIONS A 2-1. e [2.3] Use the static and final keywords [2.5] Use enumerated types Explanation: The code compiles successfully. An enum can define and use multiple constructors. The declaration of enum constants must follow the opening brace of the enum declaration. It can’t follow the definition of variables or methods. A 2-2. a, b [2.1] Identify when and how to apply abstract classes [2.2] Construct abstract Java classes and subclasses Explanation: When a class extends another class or implements an interface, the methods in the derived class must be either valid overloaded or valid overridden methods. Option (c) is incorrect. The concrete class Her extends Foo and implements Run. To compile Her, it must implement run() with public access so that it implements run() with default access in class Foo and run() with public access in interface Run: class Her extends Foo implements Run { public void run() {} } Because class Her in option (c) defines run() with default access, it fails to implement public run() from interface Run and fails compilation. Option (d) is incorrect. Method run() defined in class His and method run() defined in class Foo don’t form either valid overloaded or overridden methods. A 2-3. e [2.5] Use enumerated types Explanation: Option (a) is incorrect. The code in this option will print the natural order of the definition of the enum (the order in which they were defined): TENNIS:CRICKET:BASKETBALL:SWIMMING: Options (b), (c), and (d) define nonexistent enum methods. Code in these options won’t compile. Licensed to Mark Watson Answers to sample exam questions 167 A 2-4. a [2.4] Create top-level and nested classes [2.5] Use enumerated types Explanation: Due to the following static import statement, only the nested static class Inner is visible in class Test: import static ejava.ocp.Outer.Inner; Class Outer isn’t visible in class Test. Options (b) and (c) will instantiate class Inner if the following import statement is included in class Test: import ejava.ocp.Outer; A 2-5. a, b, d, e, f [2.4] Create top-level and nested classes Explanation: You can define final static variables in a method local inner class, but you can’t define non-final static variables, static methods, or static final methods. You can define constructors with any access modifier in a local inner class. A 2-6. a, d [2.4] Create top-level and nested classes [2.5] Use enumerated types Explanation: You can’t define an enum within a method or a nonstatic inner class. A 2-7. c [2.4] Create top-level and nested classes Explanation: To instantiate an anonymous class that can be referred to by the variable floatable of type Floatable, the anonymous class must implement the interface, implementing all its methods. Because interface Floatable defines method floating() (methods defined in an interface are implicitly public and abstract), it must be implemented by the anonymous class. Only option (c) correctly implements method floating(). Following is its correctly indented code, which should be more clear: new Floatable() { public void floating() { } }; Option (b) doesn’t implement floating(). Option (a) tries to instantiate the interface Floatable, which isn’t allowed. Option (f) looks okay, but isn’t because it makes the method floating() more restrictive by not defining it as public. Licensed to Mark Watson 168 CHAPTER 2 Advanced class design A 2-8. a, e, f [2.4] Create top-level and nested classes Explanation: Options (b) and (c) are incorrect because the class compiles successfully and prints a value. Option (d) is incorrect because it tries to instantiate the interface Admissible and not an instance of the anonymous inner class that implements Admissible. Option (e) is correct because code at (#2) instantiates an anonymous inner class, which implements the interface Admissible. Because the interface Admissible doesn’t define any methods, code at (#2) doesn’t need to implement any methods. Option (f) is correct. If Admissible is defined as a class, the anonymous inner class at (#2) will subclass it. Because Admissible doesn’t define any abstract methods, there aren’t any added complexities. A 2-9. b, c, e, f [2.1] Identify when and how to apply abstract classes Explanation: Note the use of can, must, and might or might not in these options. Note that this isn’t a test on English grammar or vocabulary. The meaning of an exam question will completely change depending on whether it uses “can” (feasible), “must” (mandatory), or “might” (optional) in a question. Option (a) is incorrect because it isn’t mandatory for an abstract class to define instance variables. Option (d) is incorrect because the constructor of all base classes—concrete or abstract—must be called by their derived classes. Option (f) is a correct statement. The combination of final and abstract modifiers is incorrect. An abstract method is meant to be overridden in the derived classes, whereas a final method can’t be overridden. A 2-10. d, g [2.4] Create top-level and nested classes Explanation: An inner class is a member of its outer class and can’t exist without its instance. To create an instance of an inner class outside either the outer or inner class, you must do the following: ■ ■ ■ If using a reference variable, use type Outer.Inner. Access an instance of the Outer class. Create an instance of the Inner class. To create instances of both the Outer and Inner classes on a single line, you must use the operator new with both the Outer class and Inner class, as follows: new Outer().new Inner(); Licensed to Mark Watson Answers to sample exam questions 169 If you already have access to an instance of Outer class, say, outer, call new Inner() by using outer: outer.new Inner(); A 2-11. c, d, e [2.4] Create top-level and nested classes Explanation: Note that you have to select incorrect statements in this question. This can be confusing, because most of the time on the exam, you’re asked to select correct options. Option (a) is a correct statement. If an anonymous inner class extends a class, it subclasses it explicitly. When it implements an interface, it implicitly extends class java.lang.Object. If an anonymous inner class doesn’t subclass a class implicitly, it implicitly extends java.lang.Object. Option (b) is a correct statement. An anonymous inner class might not always implement an interface. Option (c) is an incorrect statement. An anonymous inner class isn’t always a direct subclass of class java.lang.Object, if it extends any other class explicitly. Option (d) is an incorrect statement. You can’t make an anonymous inner class extend both a class and an interface explicitly. I deliberately used the words userdefined classes and user-defined interfaces so you wouldn’t assume that an anonymous class implicitly subclasses a class from a Java API. Option (e) is an incorrect statement. You can’t make an anonymous class implement multiple interfaces explicitly. A 2-12. d [2.2] Construct abstract Java classes and subclasses [2.3] Use the static and final keywords Explanation: No compilation or runtime issues exist with this code. A static initializer block can access and initialize a static variable; it can be placed before the static variable declaration. A static variable defined in a base class is accessible to its derived class. Even though class Moon doesn’t define the static variable ctr, it can access the static variable ctr defined in its base class Satellite. A 2-13. a [2.3] Use the static and final keywords [2.5] Use enumerated types Explanation: The creation of enum constants happens in a static initializer block, before the execution of the rest of the code defined in the static block. Here’s the decompiled code for enum BasicColor, which shows how enum constants are initialized Licensed to Mark Watson 170 CHAPTER 2 Advanced class design in the static block. To initialize an enum constant, its constructor is called. Note that the contents of the default constructor and instance initializer blocks are added to the new constructor implicitly defined during the compilation process: final class BasicColor extends Enum { public static BasicColor[] values() { return (BasicColor[])$VALUES.clone(); } public static BasicColor valueOf(String s) { return (BasicColor)Enum.valueOf(BasicColor, s); } private BasicColor(String s, int i) { super(s, i); System.out.println("Init block"); System.out.println("Constructor"); } public static void main(String args[]) { BasicColor basiccolor = RED; } public static final BasicColor RED; private static final BasicColor $VALUES[]; static { RED = new BasicColor("RED", 0); $VALUES = (new BasicColor[] { RED }); System.out.println("Static init"); } } If you try to compile the preceding code it won’t compile because classes can’t directly extend java.lang.Enum. I’ve included this code just to show you how the Java compiler modifies code of an enum and adds additional code to it. It explains why an enum constructor executes before its static block. NOTE A 2-14. a [2.5] Use enumerated types Explanation: An enum extends class java.lang.Enum, which extends class java.lang .Object. Each enum constant inherits method toString() defined in class java .lang.Enum. Class java.lang.Enum overrides method toString() to return the enum constant’s name. Licensed to Mark Watson Answers to sample exam questions 171 An enum constant can override any of the methods that are inherited by it. The enum Browser defines a constructor that accepts a String method parameter, but it doesn’t use it. All enum constants, except enum constant IE, print the name of the constant itself. A 2-15. c [2.3] Use the static and final keywords Explanation: When you instantiate a derived class, the derived class instantiates its base class. The static initializers execute when a class is loaded in memory. So the order of execution of static and instance initializer blocks is as follows: ■ ■ ■ ■ 1) Base class static initializer block 2) Derived class static initializer block 3) Base class instance initializer block 4) Derived class instance initializer block A 2-16. c, d [2.1] Identify when and how to apply abstract classes [2.3] Use the static and final keywords Explanation: Option (a) is incorrect. An abstract class can define static final variables. Option (b) is incorrect. The abstract methods defined in an abstract base class must be implemented by all its concrete derived classes. Abstract derived classes might not implement the abstract methods from their abstract base class. Option (e) is incorrect. The initialization of a final variable defined in an abstract base class must complete in the class itself—with its initialization, in its initializer block, or in its constructor. It can’t be deferred to its derived class. Licensed to Mark Watson Object-oriented design principles Exam objectives covered in this chapter What you need to know [3.1] Write code that declares, implements, and/or extends interfaces The need for interfaces. How to declare, implement, and extend interfaces. Implications of implicit modifiers that are added to an interface and its members. [3.2] Choose between interface inheritance and class inheritance The differences and similarities between implementing inheritance by using interfaces and by using abstract or concrete classes. Factors that favor using interface inheritance over class inheritance, and vice versa. [3.3] Apply cohesion, low-coupling, IS-A, and HAS-A principles Given a set of IS-A and HAS-A relationships, how to implement them in code. Given code snippets, how to correctly identify the relationships (IS-A or HAS-A) implemented by them. How to identify and promote low coupling and high cohesion. [3.4] Apply object composition principles (including HAS-A relationships) Given that an object can be composed of multiple other objects, how to determine the types of compositions— and implement them in code. [3.5] Design a class using the Singleton design pattern How to implement the Singleton design pattern. The need for the existence of exactly one copy of a class. [3.6] Write code to implement the DAO pattern The usability of the DAO pattern. How this pattern enables separation of data access code in an application. [3.7] Design and create objects using a Factory pattern The need for, use of, and benefits of a Factory for creating objects. How this pattern is used in the existing Java API classes. 172 Licensed to Mark Watson Interfaces 173 Have you ever tried to find out the secret(s) behind the most successful people? Almost all agree to follow a set of lifelong principles. So, articles like “Three Common Habits of the Most Successful People” might include points similar to these: ■ ■ ■ Never hit the snooze button when the alarm goes off in the morning, so you aren’t delaying your actions. First things first: prioritize your work. Follow your passion and do what you love, because you’ll be working almost all your life. These are the principles that successful people follow (though perhaps in a different manner) to achieve the greatest height of success. Similarly, object-oriented design (OOD) principles enable you to create better application designs, which are manageable and extensible. For example, as a programmer or designer, you know that application requirements typically change. Implementing these modified needs requires changes in the existing code, which usually introduces bugs. Chances are that if the application design implements OOD principles, the modification task will require comparatively less effort. Again, as an example, if your application’s design uses the design principles of low coupling and high cohesion, chances are low that changes in a class will affect another class. Design patterns (for example, the Singleton pattern) also help you design better applications. Unlike inheritance, a design pattern is an example of experience reuse and not code reuse. Building sloping roofs in areas that receive a lot of snowfall can be compared to using a design pattern. A sloping roof was identified as a solution to avoid accumulation of snow on rooftops after multiple people faced issues with flat roofs. Just as a sloping roof is applicable specifically to areas receiving snowfall, a design pattern resolves a specific design issue. Obviously, we can see that the object-oriented design principles are important, but what specifically do you need to know for the exam? Well, the exam will test you on what object-oriented design principles are and how to apply them in your applications. You’ll likely find questions on the creation of and preferred use of classes and interfaces to design your application, and how to relate and use Java objects together. In addition, you’ll need to know how to make the best use of design patterns in your application. Yes, this is a lot, but I promise to walk you through each piece so you’re prepared. This chapter covers ■ ■ ■ ■ ■ ■ ■ ■ Interfaces—their declaration, implementation, and application Choosing between class inheritance and interface inheritance Relationships between Java objects Application of object composition principles Implementation of IS-A and HAS-A relationships between objects Singleton design pattern Data Access Object (DAO) design pattern Factory design pattern Licensed to Mark Watson 174 CHAPTER 3 Object-oriented design principles Interfaces are one of the most powerful concepts in Java. Believe me, not many designers completely understand how to use them effectively in their design. To be a good application designer, you must know how to do so. Let’s start with a quick example: in how many ways can you refer to your father? Apart from being your father, he could also be referred to as a friend, guide, husband, swimmer, orator, teacher, manager, and much more. How can you achieve the same in Java, to refer to the same object by using multiple types? In the next section, you’ll learn about the need for using interfaces, followed by declaring, implementing, and extending them. Let’s get started. 3.1 Interfaces [3.1] Write code that declares, implements, and/or extends interfaces Before we deep-dive into working with interfaces, note that the term interface has multiple meanings. First, an interface is a type created by using the keyword interface. For example, the following code creates the interface Movable: interface Moveable { void move(); } An interface in its second meaning is more general. It’s how two systems can interact with each other (like your television and the remote control). It’s how classes can interact with each other, using their public methods. For class Person, its interface (public methods) refers to its methods eat() and work(): class Person { public void eat() {} public void work() {} } Figure 3.1 represents an interface as a type and as a group of public methods of a class. Note that this exam objective refers to an interface as a type, which is created using the keyword interface. interface Movable{ void move(); } Java type class Person{ public void eat(){} public void work(){} } Public methods Figure 3.1 The term interface has two meanings: a type created using the keyword interface and a group of public methods of a class. Licensed to Mark Watson 175 Interfaces 3.1.1 Understanding interfaces We all, quite often, use interfaces in our lives. For example, when you refer to someone as a runner, do you care whether that person is also an orator, a parent, or an entrepreneur? You care only that the person is able to run. The term runner enables you to refer to unrelated individuals, by opening a small window to each person and accessing behavior that’s applicable to only that person’s capacity as a runner. Someone can be referred to as a runner only if that person supports characteristics relevant to running, though the specific behavior can depend on the person. In the preceding example, you can compare the term runner to a Java interface, which defines the required behavior run. An interface can define a set of behaviors (methods) and constants. It delegates the implementation of the behavior to the classes that implement it. Interfaces are used to refer to multiple related or unrelated objects that share the same set of behavior. Figure 3.2 compares the interface runner with a small window to an object, which is concerned only about the running capabilities of that object. Similarly, when you design your application by using interfaces, you can use similar windows (also referred to as specifications or contracts) to specify the behavior that you need from an object, without caring about the specific type of objects. Separating the required behavior from its implementation has many benefits. As an application designer, you can use interfaces to establish the behavior that’s required from objects, promoting flexibility in the design (new classes that implement an interface can be created and used later). Interfaces make an application manageable, extensible, and less prone to propagation of errors due to changes to existing types. Orator Parent Entrepreneur work facilitate invest run guide run conferences run expand Window Runner has limited access to the objects Figure 3.2 You can compare an interface with a window that can connect multiple objects but has limited access to them. Licensed to Mark Watson 176 CHAPTER 3 Object-oriented design principles interface Runner{ int speed(); double distance = 70; } interface Runner{ Becomes public abstract int speed(); public static final double distance = 70; } Figure 3.3 All the methods of an interface are implicitly public and abstract. Its variables are implicitly public, static, and final. 3.1.2 Declaring interfaces You can define methods and constants in an interface. Declaring an interface is simple, but don’t let this simplicity take you for a ride. For the exam, it’s important to understand the implicit modifiers that are added to the members of an interface. All methods of an interface are implicitly public and abstract, and its variables are implicitly public, static, and final. Let’s start with the interface Runner that defines a method speed() and a variable distance. Figure 3.3 shows how implicit modifiers are added to the members of interface Runner during the compilation process. Why do you think these implicit modifiers are added to the interface members? Because an interface is used to define a contract, it doesn’t make sense to limit access to its members—and so they are implicitly public. An interface can’t be instantiated, and so the value of its variables should be defined and accessible in a static context, which makes them implicitly static. Because an interface is a contract, its implementations shouldn’t be able to change it, so the interface variables are implicitly final. Interface methods are implicitly abstract so that it’s mandatory for the classes to implement them. The exam will also test you on the various components of an interface declaration, including access and nonaccess modifiers. Here’s the complete list of the components of an interface declaration: ■ ■ ■ ■ ■ Access modifiers Nonaccess modifiers Interface name All extended interfaces, if the interface is extending any interfaces Interface body (variables and methods), included within a pair of curly braces {} To include all the possible components, let’s modify the declaration of the interface Runner: public strictfp interface Runner extends Athlete, Walker {} The components of the interface Runner are shown in figure 3.4. To declare any interface, you must include the keyword interface; the name of the interface; and its body, marked by {}. Licensed to Mark Watson 177 Interfaces public strictfp interface Runner extends Athlete, Walker { } Access modifier Nonaccess modifier Keyword Interface name Keyword Name of interfaces extended by interface Runner Curly braces Optional Optional Optional Optional Compulsory Compulsory Compulsory Figure 3.4 Components of an interface declaration The optional and compulsory components of an interface can be summarized as listed in table 3.1. Table 3.1 Optional and compulsory components of an interface declaration Compulsory Optional Keyword interface Access modifier Name of the interface Nonaccess modifier Interface body, marked by the opening and closing curly braces {} Keyword extends, together with the name of the base interface(s). (Unlike a class, an interface can extend multiple interfaces.) The declaration of an interface can’t include a class name. An interface can never extend any class. EXAM TIP Can you define a top-level, protected interface? No, you can’t. For the exam, you must know the answer to such questions about the correct values for each component that can be used with an interface declaration. Let’s dive into these nuances. VALID ACCESS MODIFIERS FOR AN INTERFACE You can declare a top-level interface (the one that isn’t declared within any other class or interface), with only the following access levels: ■ public ■ No modifier (default access) If you try to declare your top-level interfaces by using the other access modifiers (protected or private), your interface will fail to compile. The following definitions of the interface MyInterface won’t compile: private interface MyInterface{} protected interface MyInterface {} Top-level interface can’t be defined as private Top-level interface can’t be defined as protected Licensed to Mark Watson 178 CHAPTER 3 Object-oriented design principles All the top-level Java types (classes, enums, and interfaces) can be declared using only two access levels: public and default. Inner or nested types can be declared using any access level. EXAM TIP VALID ACCESS MODIFIERS FOR MEMBERS OF AN INTERFACE All members of an interface—variables, methods, inner interfaces, and inner classes (yes, an interface can define a class within it!)—are public by default. Interfaces support only the public access modifier. Using other access modifiers results in compilation errors. b interface MyInterface { private int number = 10; protected void aMethod(); interface interface2{} public interface interface4{} } Won’t compile Won’t compile interface2 is implicitly prefixed with public. Interface member can be prefixed with public The code at B fails compilation with the following error message: illegal combination of modifiers: public and private private int number = 10; SPECIAL CHARACTERISTICS OF METHODS AND VARIABLES OF AN INTERFACE Methods in interfaces are public and abstract by default. The following methods defined individually in an interface are equivalent: int getMembers(); public abstract int getMembers(); Variables defined in interfaces are public, static, and final by default. The following variables defined individually in an interface are equivalent: int maxMembers = 100; public static final int maxMembers = 100; Because the interface variables are implicitly final, you can define only constants in an interface. Ensure that you initialize these constants, or your code won’t compile: interface MyInterface { int number; } Won’t compile; variables within interface must be initialized. VALID NONACCESS MODIFIERS FOR AN INTERFACE You can declare a top-level interface with only the following nonaccess modifiers: ■ ■ abstract strictfp NOTE The strictfp keyword guarantees that results of all floating-point calculations are identical on all platforms. Licensed to Mark Watson 179 Interfaces If you try to declare your top-level interfaces by using the other nonaccess modifiers (final, static, transient, synchronized, or volatile), the interface will fail to compile. All of the following interface declarations fail to compile: final interface MyInterface {} static interface MyInterface {} transient interface MyInterface {} synchronized interface MyInterface {} volatile interface MyInterface {} Won’t compile; invalid nonaccess modifiers used with interface declaration A nested interface can be defined using the nonaccess modifier static (any other nonaccess modifier isn’t allowed): class Outer { static interface MyInterface1 {} } Nested interface With good coverage of interface declaration, let’s start making classes implement interfaces. 3.1.3 Implementing interfaces You can compare implementing an interface to signing a contract. When a concrete class declares its implementation of an interface, it agrees to implement all its abstract methods. A class can implement multiple interfaces. For example, class Home implements Livable and GuestHouse: abstract interface Livable { method live() void live(); } abstract method interface GuestHouse { welcome() void welcome(); } class Home implements Livable, GuestHouse { public void live() {} public void welcome() {} } Class uses keyword implements to implement interface If you don’t implement all the methods defined in the implemented interfaces, a class can’t compile as a concrete class. Let’s modify the code of class Home, as follows: class Home implements Livable, GuestHouse { public void welcome() {} } The compiler says it all: House.java:7: error: Home is not abstract and does not override abstract method live() in Livable class Home implements Livable, GuestHouse { ^ 1 error Licensed to Mark Watson 180 CHAPTER 3 Object-oriented design principles So a class can choose not to implement all the methods from the implemented interface(s) and still compile successfully, but only if it’s defined as an abstract class, as follows: abstract class Home implements Livable, GuestHouse { public void welcome() {} } Abstract class doesn’t have to implement all methods from implemented interfaces EXAM TIP A concrete class must implement all the methods from the interfaces that it implements. An abstract class can choose not to implement all the methods from the interfaces that it implements. DEFINING AND ACCESSING VARIABLES WITH THE SAME NAME A class can define an instance or a static variable with the same name as the variable defined in the interface that it implements. In the following class, the interface Livable defines variables status and ratings. Class Home implements Livable and defines instance variable status and static variable ratings, with a default access level: interface Livable { boolean status = true; public int ratings = 10; variables } class Home implements Livable { boolean status; Variables with static int ratings = 7; default access Prints Home() { “false” System.out.println(status); System.out.println(Livable.status); System.out.println(ratings); System.out.println(Livable.ratings); Prints “true” Prints “7” } Prints “11” } A class can define an instance or a static variable with the same name as the variable defined in the interface that it implements. These variables can be defined using any access level. EXAM TIP FOLLOWING METHOD OVERRIDING RULES FOR IMPLEMENTING INTERFACE METHODS The methods in an interface are public, by default. So, trying to assign weaker access to the implemented method in a class won’t allow it to compile: interface Livable { void live(); } class Home implements Livable { void live() {} } public method Won’t compile; method implemented using weaker access Licensed to Mark Watson 181 Interfaces The compilation error message says it all: House.java:8: error: live() in Home cannot implement live() in Livable void live() {} ^ attempting to assign weaker access privileges; was public 1 error EXAM TIP Because interface methods are implicitly public, the implementing class must implement them as public methods, or else the class will fail to compile. IMPLEMENTING MULTIPLE INTERFACES THAT DEFINE METHODS WITH THE SAME NAME Methods in the interfaces don’t define any implementation; they come without any baggage. But what happens if a class implements multiple interfaces that define methods with the same name? Let’s add a method live() to interface GuestHouse (modifications in bold): interface Livable { void live(); } interface GuestHouse { void welcome(); void live(); } Interface Livable defines method live(). Interface GuestHouse also defines method live(). Class Home implements two interfaces, Livable and GuestHouse, both of which define method live(): class Home implements Livable, GuestHouse { public void live() { System.out.println("live"); } public void welcome() { System.out.println("welcome"); } } Method live() in Home has only one implementation. Both the Java compiler and Java Runtime Environment are good with the preceding code. Because the signature of method live() is the same in both interfaces, Livable and GuestHouse, class Home needs to define only one implementation for method live() to fulfill both contracts (interface implementations). OVERLAPPING METHOD IMPLEMENTATIONS WITH THEIR OVERLOAD VERSIONS A class can try to implement multiple interfaces that define methods with the same name. But in doing so, you can have a not-so-pleasant cocktail of overlapping method implementations and their overloaded versions. We have two scenarios here: ■ ■ Correctly overloaded methods Invalid overloaded methods Licensed to Mark Watson 182 CHAPTER 3 Object-oriented design principles Overloaded methods are defined by using the same name but a different parameter list. For example, when implemented in class Home, method live() defined in the interface Livable overloads method live() defined in the interface GuestHouse. Class Home must implement both these methods: interface Livable { void live(); live() doesn’t accept any } method parameters. interface GuestHouse { void live(int days); live() accepts a } method parameter. class Home implements Livable, GuestHouse { public void live() { Correctly overloaded System.out.println("live"); method live() from Livable } public void live(int days) { Correctly overloaded System.out.println("live for " + days); method live() from } GuestHouse } You can’t define overloaded methods by changing only the return type of methods. What happens if method live() in the interfaces Livable and GuestHouse returns different types? In this case, class Home needs to implement both versions of method live(), which can’t be qualified as overloaded methods. So class Home doesn’t compile in this case: live() returns interface Livable { String. String live(); } live() returns interface GuestHouse { nothing—void. void live(); } class Home implements Livable, GuestHouse { public String live() { return null; } public void live() { System.out.println("live" ); } } Class Home won’t compile. When implemented in class Home, both versions of live() qualify as incorrectly overloaded methods. Here’s the compiler error for class Home: Home.java:11: error: method live() is already defined in class Home public void live() { ^ Home.java:7: error: Home is not abstract and does not override abstract method live() in GuestHouse class Home implements Livable, GuestHouse { ^ Licensed to Mark Watson 183 Interfaces Home.java:8: error: live() in Home cannot implement live() in GuestHouse public String live() { ^ return type String is not compatible with void 3 errors A class can implement methods with the same name from multiple interfaces. But these must qualify as correctly overloaded methods. EXAM TIP 3.1.4 Extending interfaces An interface can inherit multiple interfaces. Because all the members of an interface are implicitly public, a derived interface inherits all the methods of its super interface(s). An interface uses the keyword extends to inherit an interface, as shown in the following example: interface GuestHouse { void welcome(); } interface PayingGuestHouse extends GuestHouse { void paidBreakfast(); } interface StudentPGHouse extends PayingGuestHouse { void laundry(); } interface ChildFriendly { void toys(); } interface FamilyPGHouse extends ChildFriendly, PayingGuestHouse { void kitchen(); } The preceding code is shown in figure 3.5 as a UML diagram. < > GuestHouse +welcome() < > <