- •Contents at a Glance
- •Contents
- •About the Authors
- •About the Technical Reviewer
- •Acknowledgments
- •Introduction
- •Oracle Java Certifications: Overview
- •FAQ 1. What are the different levels of Oracle Java certification exams?
- •FAQ 4. Is OCPJP 7 prerequisite for other Oracle certification exams?
- •FAQ 5. Should I take the OCPJP 7 or OCPJP 6 exam?
- •The OCPJP 7 Exam
- •FAQ 7. How many questions are there in the OCPJP 7 exam?
- •FAQ 8. What is the duration of the OCPJP 7 exam?
- •FAQ 9. What is the cost of the OCPJP 7 exam?
- •FAQ 10. What are the passing scores for the OCPJP 7 exam?
- •FAQ 11. What kinds of questions are asked in the OCPJP 7 exam?
- •FAQ 12. What does the OCPJP 7 exam test for?
- •FAQ 13. I’ve been a Java programmer for last five years. Do I have to prepare for the OCPJP 7 exam?
- •FAQ 14. How do I prepare for the OCPJP 7 exam?
- •FAQ 15. How do I know when I’m ready to take the OCPJP 7 exam?
- •Taking the OCPJP 7 Exam
- •FAQ 16. What are my options to register for the exam?
- •FAQ 17. How do I register for the exam, schedule a day and time for taking the exam, and appear for the exam?
- •The OCPJP 7 Exam: Pretest
- •Answers with Explanations
- •Post-Pretest Evaluation
- •Essentials of OOP
- •FunPaint Application: An Example
- •Foundations of OOP
- •Abstraction
- •Encapsulation
- •Inheritance
- •Polymorphism
- •Class Fundamentals
- •Object Creation
- •Constructors
- •Access Modifiers
- •Public Access Modifier
- •Private Access Modifier
- •Protected and Default Access Modifier
- •Overloading
- •Method Overloading
- •Constructor Overloading
- •Overload resolution
- •Points to Remember
- •Inheritance
- •Runtime Polymorphism
- •An Example
- •Overriding Issues
- •Overriding: Deeper Dive
- •Invoking Superclass Methods
- •Type Conversions
- •Upcasts and Downcasts
- •Casting Between Inconvertible Types
- •Using “instanceof” for Safe Downcasts
- •Java Packages
- •Working with Packages
- •Static Import
- •Summary
- •Abstract Classes
- •Points to Remember
- •Using the “final” Keyword
- •Final Classes
- •Final Methods and Variables
- •Points to Remember
- •Using the “static” Keyword
- •Static Block
- •Points to Remember
- •Flavors of Nested Classes
- •Static Nested Classes (or Interfaces)
- •Points to Remember
- •Inner Classes
- •Points to Remember
- •Local Inner Classes
- •Points to Remember
- •Anonymous Inner Classes
- •Points to Remember
- •Enum Data Types
- •Points to Remember
- •Summary
- •Interfaces
- •Declaring and Using Interfaces
- •Points to Remember
- •Abstract Classes vs. Interfaces
- •Choosing Between an Abstract Class and an Interface
- •Object Composition
- •Composition vs. Inheritance
- •Points to Remember
- •Design Patterns
- •The Singleton Design Pattern
- •Ensuring That Your Singleton Is Indeed a Singleton
- •The Factory Design Pattern
- •Differences Between Factory and Abstract Factory Design Patterns
- •The Data Access Object (DAO) Design Pattern
- •Points to Remember
- •Summary
- •Generics
- •Using Object Type and Type Safety
- •Using the Object Class vs. Generics
- •Container Implementation Using the Object Class
- •Container Implementation Using Generics
- •Creating Generic Classes
- •Diamond Syntax
- •Interoperability of Raw Types and Generic Types
- •Generic Methods
- •Generics and Subtyping
- •Wildcard Parameters
- •Limitations of Wildcards
- •Bounded Wildcards
- •Wildcards in the Collections Class
- •Points to Remember
- •The Collections Framework
- •Why Reusable Classes?
- •Basic Components of the Collections Framework
- •Abstract Classes and Interfaces
- •Concrete Classes
- •List Classes
- •ArrayList Class
- •The ListIterator Interface
- •The LinkedList Class
- •The Set Interface
- •The HashSet Class
- •The TreeSet Class
- •The Map Interface
- •The HashMap Class
- •Overriding the hashCode() Method
- •The NavigableMap Interface
- •The Queue Interface
- •The Deque Interface
- •Comparable and Comparator Interfaces
- •Algorithms (Collections Class)
- •The Arrays Class
- •Methods in the Arrays Class
- •Array as a List
- •Points to Remember
- •Summary
- •Generics
- •Collections Framework
- •Processing Strings
- •String Searching
- •The IndexOf() Method
- •The regionMatches() Method
- •String Parsing
- •String Conversions
- •The Split() Method
- •Regular Expressions
- •Understanding regex Symbols
- •Regex Support in Java
- •Searching and Parsing with regex
- •Replacing Strings with regex
- •String Formatting
- •Format Specifiers
- •Points to Remember
- •Summary
- •Reading and Writing from Console
- •Understanding the Console Class
- •Formatted I/O with the Console Class
- •Special Character Handling in the Console Class
- •Using Streams to Read and Write Files
- •Character Streams and Byte Streams
- •Character Streams
- •Reading Text Files
- •Reading and Writing Text Files
- •“Tokenizing” Text
- •Byte Streams
- •Reading a Byte Stream
- •Data Streams
- •Writing to and Reading from Object Streams: Serialization
- •Serialization: Some More Details
- •Points to Remember
- •Summary
- •A Quick History of I/O APIs
- •Using the Path Interface
- •Getting Path Information
- •Comparing Two Paths
- •Using the Files Class
- •Checking File Properties and Metadata
- •Copying a File
- •Moving a File
- •Deleting a File
- •Walking a File Tree
- •Revisiting File Copy
- •Finding a File
- •Watching a Directory for Changes
- •Points to Remember
- •Summary
- •Introduction to JDBC
- •The Architecture of JDBC
- •Two-Tier and Three-Tier JDBC Architecture
- •Types of JDBC Drivers
- •Setting Up the Database
- •Connecting to a Database Using a JDBC Driver
- •The Connection Interface
- •Connecting to the Database
- •Statement
- •ResultSet
- •Querying the Database
- •Updating the Database
- •Getting the Database Metadata
- •Points to Remember
- •Querying and Updating the Database
- •Performing Transactions
- •Rolling Back Database Operations
- •The RowSet Interface
- •Points to Remember
- •Summary
- •Define the Layout of the JDBC API
- •Connect to a Database by Using a JDBC driver
- •Update and Query a Database
- •Customize the Transaction Behavior of JDBC and Commit Transactions
- •Use the JDBC 4.1 RowSetProvider, RowSetFactory, and RowSet Interfaces
- •Introduction to Exception Handling
- •Throwing Exceptions
- •Unhandled Exceptions
- •Try and Catch Statements
- •Programmatically Accessing the Stack Trace
- •Multiple Catch Blocks
- •Multi-Catch Blocks
- •General Catch Handlers
- •Finally Blocks
- •Points to Remember
- •Try-with-Resources
- •Closing Multiple Resources
- •Points to Remember
- •Exception Types
- •The Exception Class
- •The RuntimeException Class
- •The Error Class
- •The Throws Clause
- •Method Overriding and the Throws Clause
- •Points to Remember
- •Custom Exceptions
- •Assertions
- •Assert Statement
- •How Not to Use Asserts
- •Summary
- •Introduction
- •Locales
- •The Locale Class
- •Getting Locale Details
- •Resource Bundles
- •Using PropertyResourceBundle
- •Using ListResourceBundle
- •Loading a Resource Bundle
- •Naming Convention for Resource Bundles
- •Formatting for Local Culture
- •The NumberFormat Class
- •The Currency Class
- •The DateFormat Class
- •The SimpleDateFormat Class
- •Points to Remember
- •Summary
- •Introduction to Concurrent Programming
- •Important Threading-Related Methods
- •Creating Threads
- •Extending the Thread Class
- •Implementing the Runnable Interface
- •The Start( ) and Run( ) Methods
- •Thread Name, Priority, and Group
- •Using the Thread.sleep() Method
- •Using Thread’s Join Method
- •Asynchronous Execution
- •The States of a Thread
- •Two States in “Runnable” State
- •Concurrent Access Problems
- •Data Races
- •Thread Synchronization
- •Synchronized Blocks
- •Synchronized Methods
- •Synchronized Blocks vs. Synchronized Methods
- •Deadlocks
- •Other Threading Problems
- •Livelocks
- •Lock Starvation
- •The Wait/Notify Mechanism
- •Let’s Solve a Problem
- •More Thread States
- •timed_waiting and blocked States
- •waiting State
- •Using Thread.State enum
- •Understanding IllegalThreadStateException
- •Summary
- •Using java.util.concurrent Collections
- •Semaphore
- •CountDownLatch
- •Exchanger
- •CyclicBarrier
- •Phaser
- •Concurrent Collections
- •Apply Atomic Variables and Locks
- •Atomic Variables
- •Locks
- •Conditions
- •Multiple Conditions on a Lock
- •Use Executors and ThreadPools
- •Executor
- •Callable, Executors, ExecutorService, ThreadPool, and Future
- •ThreadFactory
- •The ThreadLocalRandom Class
- •TimeUnit Enumeration
- •Use the Parallel Fork/Join Framework
- •Useful Classes of the Fork/Join Framework
- •Using the Fork/Join Framework
- •Points to Remember
- •Summary
- •Using java.util.concurrent Collections
- •Applying Atomic Variables and Locks
- •Using Executors and ThreadPools
- •Using the Parallel Fork/Join Framework
- •Chapter 3: Java Class Design
- •Chapter 4: Advanced Class Design
- •Chapter 5: Object-Oriented Design Principles
- •Chapter 6: Generics and Collections
- •Chapter 7: String Processing
- •Chapter 8: Java I/O Fundamentals
- •Chapter 9: Java File I/O (NIO.2)
- •Chapter 10: Building Database Applications with JDBC
- •Chapter 11: Exceptions and Assertions
- •Chapter 12: Localization
- •Chapter 13: Threads
- •Chapter 14: Concurrency
- •OCPJP7 Exam (1Z0-804 a.k.a. Java SE 7 Programmer II) Topics
- •OCPJP 7 Exam (1Z0-805, a.k.a. Upgrade to Java SE 7 Programmer) Topics
- •Answers and Explanations
- •Answer Sheet
- •Answers and Explanations
- •Index
Chapter 3 ■ Java Class Design
class Circles { |
|
|
|
void getArea() { |
|
|
|
Circle |
circle = new Circle(); |
||
circle.area(); |
// call to public method area() within package |
||
circle.fillColor(); |
// call to a method with default access modifier |
||
within package |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Canvas.java |
|
|
|
package appcanvas; |
|
|
|
import graphicshape.Circle; |
|
|
|
|
|
|
|
class Canvas { |
|
|
|
void getArea() { |
|
|
|
Circle |
circle = new Circle(); |
||
circle.area(); |
// call to public method area(), outside package |
}
}
As the example shows, the protected field color is accessed in the class Circle and the default method fillColor() is called from the class Circles.
The visibility offered by various access modifiers is summarized in Table 3-1.
Table 3-1. Access Modifiers and Their Visibility
|
|
|
|
|
|
Access modifiers/ |
Within the |
Subclass inside |
Subclass outside |
Other class inside |
Other class outside |
accessibility |
same class |
the package |
the package |
the package |
the package |
Public |
Yes |
Yes |
Yes |
Yes |
Yes |
Private |
Yes |
No |
No |
No |
No |
Protected |
Yes |
Yes |
Yes |
Yes |
No |
Default |
Yes |
Yes |
No |
Yes |
No |
|
|
|
|
|
|
It is important to note that a class (or interface) cannot be declared as private or protected. Furthermore, member methods or fields of an interface cannot be declared as private or protected.
Overloading
Now let’s enlarge on the concept of polymorphism introduced in the “Polymorphism” section above. Polymorphism can be of two forms: static and dynamic. When different forms of a single entity are resolved at
compile time (early binding), such polymorphism is called static polymorphism. When different forms of a single entity are resolved during runtime (late binding), such polymorphism is called dynamic polymorphism. Overloading is an example of static polymorphism.
55
Chapter 3 ■ Java Class Design
Method Overloading
In a class, how many methods can you define with the same name? Many! In Java, you can define multiple methods with the same name, provided the argument lists differ from each other. In other words, if you provide different types of arguments, different numbers of arguments, or both, then you can define multiple methods with the same name. This feature is called method overloading. The compiler will resolve the call to a correct method depending on the actual number and/or types of the passed parameters.
In the FunPaint application, you can draw and color a shape. Say you want to color a circle. How would you define a method that can implement this functionality? (Please note that any color can be specified using one of these two approaches.)
1.By combining the basic colors of red, green, and blue. This approach is known as RGB scheme. By convention, each of the color values is typically given in the range 0 to 255.
2.By giving hue, saturation, and brightness values. This approach is known as HSB scheme. By convention, each of the values is typically given in the range 0.0 to 1.0.
Let’s implement a method in the Circle class called fillColor() that takes RGB or HSB values. Since RGB values are integer values and HSB values are floating point values, how about supporting both these schemes for calling fillColor() method? See Listing 3-5.
Listing 3-5. Circle.java
class Circle {
// other members
public void fillColor (int red, int green, int blue) {
/* color the circle using RGB color values – actual code elided */
}
public void fillColor (float hue, float saturation, float brightness) { /* color the circle using HSB values – actual code elided */
}
}
As you can see, both fillColor() methods have exactly the same name and both take three arguments; however, the argument types are different. Based on the type of arguments used while calling fillColor() method on Circle, the compiler will decide exactly which method to call. For instance, consider following method calls:
Circle c1 = new Circle(10, 20, 10); c1.fillColor(0, 255, 255);
Circle c2 = new Circle(50, 100, 5); c2.fillColor(0.5f, 0.5f, 1.0f);
In this code, for the c1 object, the call to fillColor() has integer arguments 0, 255, and 255. Hence, the compiler resolves this call to the method fillColor (int red, int green, int blue). For the c2 object, the call to fillColor() has arguments 0.5f, 0.5f, and 1.0f; hence it resolves the call to fillColor (float hue, float saturation, float brightness).
In the above example, method fillColor() is an overloaded method. The method has same name and the same number of arguments, but the types of the arguments differ. It is also possible to overload methods with different numbers of arguments.
Such overloaded methods are useful for avoiding repeating the same code in different functions. Let’s look at a simple example in Listing 3-6.
56
Chapter 3 ■ Java Class Design
Listing 3-6. HappyBirthday.java
class HappyBirthday {
//overloaded wish method with String as an argument public static void wish(String name) {
System.out.println("Happy birthday " + name + "!");
}
//overloaded wish method with no arguments; this method in turn invokes wish(String) method public static void wish() {
wish("to you");
}
public static void main(String []args) { wish();
wish("dear James Gosling");
}
}
It prints:
Happy birthday to you!
Happy birthday dear James Gosling!
Here, the method wish(String name) is meant for wishing “Happy Birthday” when the name of the person is known. The default method wish() is for wishing “Happy Birthday” to anyone. As you can see, you don’t have to write System.out.println again in the wish() method; you can just reuse the wish(String) method definition by passing the default value “to you” as argument to wish(). Such reuse is effective for large and related method definitions since it saves time writing and testing the same code.
Constructor Overloading
A default constructor is useful for creating objects with a default initialization value. When you want to initialize the objects with different values in different instantiations, you can pass them as the arguments to constructors. And yes, you can have multiple constructors in a class—which is constructor overloading. In a class, the default constructor can initialize the object with default initial values, while another constructor can accept arguments that need to be used for object instantiation.
In the FunPaint application, the user can just drag and drop the Circle template in the screen to create a Circle object. In that case, you must set the xPos and yPos values for that dropped position and assume a default value for radius (Listing 3-7).
Listing 3-7. Circle.java
//a Circle object can be created by dragging and dropping a circle template
//the x, and y positions need to be set in that case, but a default radius value can be assumed public Circle(int x, int y) {
xPos = x; yPos = y;
radius = 10; // default radius
}
57
Chapter 3 ■ Java Class Design
Let’s retain the toString() method that was defined in the previous section on default constructors:
public String toString() {
return "center = (" + xPos + "," + yPos + ") and radius = " + radius;
}
While creating the object, you can pass the arguments, as in the following statement:
System.out.println(new Circle(50, 100).toString());
The above statement prints
center = (50,100) and radius = 10
Now, can you see what is wrong with the following constructor implementation?
public Circle(int xPos, int yPos) { xPos = xPos;
yPos = yPos;
radius = 10; // default radius
}
System.out.println(new Circle(50, 100));
It prints
center = (0, 0) and radius = 10
What happened? You just changed the name of arguments in the constructor given in the previous example, and it doesn’t work!
The statement xPos = xPos; is the culprit. What you wanted was to assign the member xPos to the passed argument value xPos. However, this statement reassigns the passed argument value xPos! A passed argument is treated just like a local variable (a variable confined to local scope). If there is a local variable with same name as the field, the local variable hides the field.
In order to avoid subtle bugs, refrain from reusing the same variable names across scopes.
How can you solve this issue? You can rename the argument instead of using xPos, say x. Or you can use this to qualify the use of xPos, as in
public Circle(int xPos, int yPos) { this.xPos = xPos; this.yPos = yPos;
radius = 10; // default radius
}
58
Chapter 3 ■ Java Class Design
In the statement this.xPos = xPos;, you explicitly qualify the variable xPos with this, so the LHS (left-hand side) of the statement refers to the field and the RHS (right-hand side) of the statement refers to the parameter name.
Use the explicit this qualifier when accessing fields inside instance methods or constructors to avoid ambiguity in referring to variable names.
Create another constructor of Circle by passing more parameters. You’ll also pass the radius value.
public Circle(int x, int y, int r) { xPos = x;
yPos = y; radius = r;
}
Now you’ll write the main() method, and you’ll create some Circle objects in it. You’ll implement the toString() method to print the center position and the radius (see Listing 3-8).
Listing 3-8. Circle.java
public class Circle { private int xPos; private int yPos; private int radius;
// three overloaded constructors for Circle public Circle(int x, int y, int r) {
xPos = x; yPos = y; radius = r;
}
public Circle(int x, int y) { xPos = x;
yPos = y;
radius = 10; // default radius
}
public Circle() {
xPos = 20; // assume some default values for xPos and yPos yPos = 20;
radius = 10; // default radius
}
public String toString() {
return "center = (" + xPos + "," + yPos + ") and radius = " + radius;
}
59