Graded Project
Final Graded Project
OVERVIEW 1
YOUR PROJECT 1
SUBMISSION GUIDELINES 2
iii
C o n t e n t s
C o n t e n t s
1
OVERVIEW
Now that you’ve completed the study guide and required textbook reading, you’re ready to finish the TicTacToe game in the final project. You’ll add the application logic to handle each turn and determine the outcome of the game.
Make sure that you follow all directions completely and verify your results before submitting the project. Remember to include all required components in your solution.
YOUR PROJECT
In this project, you’ll finish the GUI version of the Tic-Tac-Toe game. This project will require you to rewrite the application logic found in the graded project for Lesson 2, but using object orientation this time. In the instructions, code will be refer- enced from the previous graded projects.
Instructions
1. In NetBeans, open the TicTacToeGUIGame project.
2. In the TicTacToeGUIGame.java file, make the following changes to the TicTacToeGUIGame class:
a. Add a new method named getOutcome that returns an Outcome enumeration. Use the winOrTie method in the Lesson 2 graded project as a guide.
b. In the takeTurn method, use the getOutcome method to determine whether to continue the game.
Final Graded Project
c. In the takeTurn method, display a dialog message that displays the winner or tie when the game ends. Optionally, you can clear the board and start a new game after it ends.
Note: You can use the following method to display a dialog message in the current window:
JOptionPane.showMessageDialog (this, “Both players tie.”);
3. Build and run the project. Verify it works as expected. Don’t be discouraged if it doesn’t run as expected right away. Try tracing your steps and using System.out.write statements to figure out where you went wrong.
SUBMISSION GUIDELINES
For your project, you should submit the final JAR file:
TicTacToeGUIGame.jar
To ensure the JAR file is built, you should click the Build button or hit the F11 key.
To find the JAR file with NetBeans, you need to go to the TicTacToeGUIGame project folder. To determine this folder, right-click on TicTacToeGUIGame project in the Projects panel. Copy the value for the Project Folder textbox using the keyboard shortcut CTRL+C. In Windows Explorer, paste the project folder path and hit the ENTER key. Copy the TicTacToeGUIGame.jar file from the dist folder to your desktop or any other temporary location.
Follow this procedure to submit your project online:
1. Log on to the Penn Foster website and go to My Courses.
2. Click Take Exam.
3. Attach your file as follows:
a. Click on the Browse box.
b. Locate the file you wish to attach.
c. Double-click on the file.
d. Click Upload File.
Graded Project Title2
4. Enter your e-mail address in the box provided. (Note: This information is required for online submissions.)
5. If you wish to tell your instructor anything specific regarding this assignment, enter it in the Message box.
6. Click Submit File.
Grading Criteria
Your instructor will use the following guidelines to grade your project.
Application behaves as expected 40 points
GUI meets the requirements 30 points
File contains no syntax errors 30 points
TOTAL 100 points
Congratulations! You’ve completed a simple application with a GUI. You could expand on this game by adding more graphics or animation or develop a new game like Connect Four or Mastermind.
Now, you are ready to take on the larger world of Java development!
Graded Project # 3
Study Guide
Programming in Java By
Joshua Hester
About the Author
Joshua Hester is a content developer for Kaplan IT Learning and a certified trainer for Microsoft and Certified Internet Webmaster pro- grams. He has written, talked, taught, and breathed code for more than 15 years. After mastering BASIC with a Commodore 64 and pushing his website development on people throughout college, he has now evolved into Java Structs, the Microsoft 4 Framework, and other Web 2.0 technologies.
Mr. Hester is a certified Project Management Professional, Linux Professional, and Microsoft Office Specialist; he also holds certifica- tions for A+, Linux+, Network+, and i-Net+. He earned a bachelor of arts in English from Colgate University and is currently pursuing a masters of education in instructional technology from Kaplan University. Besides looking for more certifications, he’s an avid runner and gamer and enjoys biking, hiking, and solving the odd logic puzzle.
Copyright © 2013 by Penn Foster, Inc.
All rights reserved. No part of the material protected by this copyright may be reproduced or utilized in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage and retrieval system, without permission in writing from the copyright owner.
Requests for permission to make copies of any part of the work should be mailed to Copyright Permissions, Penn Foster, 925 Oak Street, Scranton, Pennsylvania 18515.
Printed in the United States of America
All terms mentioned in this text that are known to be trademarks or service marks have been appropriately capitalized. Use of a term in this text should not be regarded as affecting the validity of any trademark or service mark.
INSTRUCTIONS TO STUDENTS 1
LESSON ASSIGNMENTS 5
LESSON 1: INTRODUCTION TO THE JAVA LANGUAGE 7
GRADED PROJECT—LESSON 1 29
LESSON 2: DATA TYPES AND PROGRAM CONTROL 33
GRADED PROJECT—LESSON 2 71
LESSON 3: OBJECT- ORIENTED PROGRAMMING 79
GRADED PROJECT—LESSON 3 133
LESSON 4: ADVANCED PROGRAMMING LOGIC 141
GRADED PROJECT—LESSON 4 165
LESSON 5: GRAPHICAL USER INTERFACE DESIGN 169
GRADED PROJECT—LESSON 5 195
SELF-CHECK ANSWERS 201
iii
C o
n t
e n
t s
C o
n t
e n
t s
1
In s
tr u
c tio
n s
In s
tr u
c tio
n s
YOUR COURSE
Like watching a nimble artisan, you can’t learn Java by mere observation. You must practice. This course will introduce Java development by immersion. Each lesson builds upon the previous one, layering concepts and growing skills—not through passive interpretation, but by writing real-world applications. The first few lessons will gently inch you into the rich development world of Java, but by the end of the course, you’ll have a fully functional application and the associated skillset to create many more.
The textbook for the course is Java: A Beginner’s Guide, Fifth Edition, by Herbert Schildt. This study guide accompanies the textbook by providing reading assignments, additional resources, insights and highlights, and step-by-step activities and self-check questions to build skills and test your progress. The answers to the self-check questions are at the end of the study guide. The textbook also includes Try This activities and Self-Test questions in each chapter to provide additional practice.
The course is divided into five lessons, each with assignments and a graded project. The first three lessons will provide a foundation for using the Java language, while the last two will move into specific Java frameworks. With the exception of the first graded project, each subsequent graded project will build upon the other. The final graded project is the summary for the course, requiring you to apply your learned Java knowledge and skills to an application built from the ground up.
PREREQUISITES
This course assumes that you understand computer components, are familiar with text editor applications, have experience with programming languages other than Java, and have had some exposure with object-oriented programming and design. If these prerequisites are a bit rusty, then you might find Oracle’s Java Tutorials (http://docs.oracle.com/ javase/tutorial/index.html) a helpful supplement to the textbook and study guide.
When you complete this course, you’ll be able to
■ Write, compile, and run Java code
■ Implement common coding algorithms in Java
■ Create applications with object-oriented design principles
■ Use Java I/O and multithreading in applications
■ Create applets and Swing-based applications
YOUR TEXTBOOK
The textbook is Java: A Beginner’s Guide, Fifth Edition, by Herbert Schildt. It contains a thorough introduction to Java development and is a great preparation material for the Oracle Java SE 7 Programmer certification. Java development is divided into 16 chapters, starting with the runtime basics and concluding with Swing. Answers to Self-Test questions are found in the back of the book along with Java documentation comments and an index.
COURSE MATERIALS
The main course materials are this study guide and the textbook. The study guide consists of the following:
■ Reading assignments for each lesson
■ Lessons that emphasize and augment the reading
■ Activities to perform tasks and apply your learning
■ Self-check questions and answers to assess your learning
■ Graded projects for each lesson
Instructions to Students2
A STUDY PLAN
Everyone has his or her own style of learning. The object is to find the method of learning that works best for you. What follows is a suggested format for using this study guide. Remember that it’s only a suggested plan. If you feel that another method would help you learn more effectively, by all means use that method.
This course divides the material to be covered into five lessons. Each lesson is divided into multiple assignments to make your learning more manageable. Each assignment includes a read- ing from your textbook and a supplementary assignment in this study guide. For most assignments, there are self-check questions to check your understanding of what you’ve learned. Be sure to complete all of the work in each lesson before moving on to the next. You’ll find this easy to do if you follow the plan of study outlined below.
1. Note the textbook pages for each assignment and read the summary material in this study guide.
2. Quickly read the assigned pages in your textbook. This is called skimming, and it’s a learning technique you should use to get a general idea of the topics covered in that part of the text.
3. Go back and slowly read the assigned textbook pages again. Pay careful attention to what you’re reading. Keep in mind the learning objectives and how the material relates to them. Pay particular attention to definitions and main concepts.
4. Answer the questions and problems provided in the self- checks in the study guide. This will serve as a review of the material covered. The self-checks are an integral part of the assignment. Don’t move on to the next assignment without taking the self-check. These questions are for your use only—they aren’t graded. Don’t send your answers to the school.
Instructions to Students 3
5. Once you’ve completed a self-check, turn to the answers provided at the back of this study guide. The self-checks are designed to show you how well you understand the material, so test yourself honestly. Make every effort to complete the questions before turning to the answers at the back of this study guide. If you find any weak areas in your knowledge, go back and review the relevant material until you understand it.
6. Follow this procedure for the next assignments, until you’ve completed the lesson.
7. When you’re confident that you understand all the assigned material within a lesson, complete the examination or graded project for that lesson. The examination is based on both your textbook and this study guide.
8. Follow this procedure for all six lessons. If you have any questions during your studies, e-mail your instructor for assistance. You’re now ready to begin your study of Java programming. Good luck!
Instructions to Students4
Remember to regularly check “My Courses” on your student homepage. Your instructor may post additional resources that you can access to enhance your learning experience.
Lesson 1: Introduction to the Java Language For: Read in the Read in the
study guide: textbook:
Assignment 1 Pages 7–11 Pages 1–10
Assignment 2 Pages 13–18 Pages 10–11
Assignment 3 Pages 19–28 Pages 12–30
Graded Project 40259400 Material in Lesson 1
Lesson 2: Data Types and Program Control For: Read in the Read in the
study guide: textbook:
Assignment 4 Pages 34–47 Chapter 2; Pages 158–164; 166–176
Assignment 5 Pages 48–59 Chapter 3; Pages 110–117; 176–177; 194–199
Assignment 6 Pages 60–65 Pages 136–158
Assignment 7 Pages 66–69 Chapter 9
Graded Project 40259500 Material in Lesson 2
Lesson 3: Object-Oriented Programming For: Read in the Read in the
study guide: textbook:
Assignment 8 Pages 80–96 Pages 104–110; 124–134; Chapter 6
Assignment 9 Pages 97–114 Chapter 7; Pages 268–278; 427–429
Assignment 10 Pages 115–123 Pages 278–292; 406–420
Assignment 11 Pages 125–131 Pages 420–426; Chapter 13
Graded Project 40259600 Material in Lesson 3
5
A s
s ig
n m
e n
ts A
s s
ig n
m e
n ts
Lesson 4: Advanced Programming Logic For: Read in the Read in the
study guide: textbook:
Assignment 12 Pages 142–153 Chapter 10
Assignment 13 Pages 154–163 Chapter 11
Graded Project 40259700 Material in Lesson 4
Lesson 5: Graphical User Interface Design For: Read in the Read in the
study guide: textbook:
Assignment 14 Pages 170–182 Pages 473–496; 536–537
Assignment 15 Pages 183–193 Chapter 15
Graded Project 40259800 Material in Lesson 5
Lesson Assignments6
Note: To access and complete any of the examinations for this study guide, click on the appropriate Take Exam icon on your “My Courses” page. You should not have to enter the examination numbers. These numbers are for reference only if you have reason to contact Student Services.
7
L e
s s
o n
1 L
e s
s o
n 1
Introduction to the Java Language
INTRODUCTION
There’s no better way to learn how to program in a new lan- guage than to dive in! In this lesson, you’ll be introduced to the Java language and runtime environment and you’ll tour the NetBeans IDE. You’ll be writing, compiling, and running your first Java application by its conclusion.
OBJECTIVES
When you complete this lesson, you’ll be able to
■ Explain how procedural languages differ from object-oriented languages
■ Identify the main characteristics of Java technology
■ Install the Java Standard Edition 7 Runtime Environment
■ Identify language rules and common conventions in Java
■ Write, compile, and execute a simple Java program using the NetBeans IDE
ASSIGNMENT 1: A BRIEF OVERVIEW OF PROGRAMMING Read Assignment 1 in this study guide. Then, read pages 1–10 in your textbook.
The Procedural Approach
This assignment is an overview of basic programming approaches and introduces the Java language. The textbook assignment recounts the history of Java and reviews important concepts in high-level object-oriented programming (OOP).
Programming in Java8
The goal of programming is to solve problems. In the proce- dural approach, the solution involves executing instructions step by step. Each step may modify some data, but the data and instructions are stored separately. Data can be stored in structures such as arrays, sets, or records, while instructions are grouped into procedures, and procedures are further grouped into modules. Procedures and modules allow pro- grammers to reuse code to reduce repetition and increase manageability.
Take the example of making a fresh cup of coffee with a coffee press. The data would include the amount of coffee beans and boiling water, whether the beans were ground or whole, and the time to boil the water and let the coffee brew. The instructions would include the following steps:
■ Measure the amount of beans and water.
■ Place the beans in the grinder.
■ Grind the beans in the grinder.
■ Place the water to boil on the stove.
■ Place the ground beans in the coffee press.
You get the idea. These and other instructions could then become simple procedures named Boil(), Measure(), Grind(), Move(), Brew(), and Pour() in a module named Coffee. The approach focuses on action and which data is required to perform the actions.
A number of early languages, such as BASIC, COBOL, C, and FORTRAN, implement this approach. The more modern languages like Scala, Lisp, and F# implement a variation on this approach, known as functional programming. Unlike traditional procedural programming, functional programming languages support additional built-in mathematical functions and out-of-order execution for instructions.
The Object-Oriented Approach
The object-oriented approach is more abstract and less declar- ative than the procedural approach. Data and instructions are combined into entities that resemble real-world objects. The
Lesson 1 9
data is stored as attributes of the object, while instructions are grouped into its methods. Objects can have complex rela- tionships and interdependencies to optimize scalability and reduce overall redundancy. In object-oriented design, a class is a blueprint for objects, describing which attributes and methods each object will support. Attributes are also known as fields in Java.
Continuing with the coffee press example, an object-oriented approach would first capture the real-world objects involved, which include the beans, grinder, water, and coffee press. The next step would be to determine which attributes each object requires. Coffee beans can be either whole or ground, so a field would need to represent that. Water can be either boiling or not boiling, and a coffee press can be brewing coffee, containing only beans, or empty. Like the procedural approach, measurements are tracked, but in object-orientation, each object tracks its own data. Finally, the methods need to be determined for each object. The methods are very similar to the procedures described previously, except they’re stored in an object and usually require fewer arguments. For example, the Grinder object would contain a method named grind() that needs to know only how many beans to grind.
Most compiled languages and increasingly a number of scripting languages as well, implement this approach. Unlike C++ and Visual Basic, in which object-orientation was bolted onto an existing procedural language, Java is built from the ground up on object-oriented programming. As you’ll see, even the simplest of programs requires a class and the main() method to execute.
The Java Approach
One of the early slogans for Java was “write once, run anywhere.” Java programs can run on diverse platforms—from standard desktop and laptop computers to mobile phones and tablets. The current high definition standard even supports Java running from BluRay discs!
When Java was introduced in 1995, most programming languages targeted a specific platform. Conversely, Java applications are platform-agnostic, meaning the developer only needs to learn Java, not keep track of the particulars of a specific CPU,
Programming in Java10
motherboard, chipset, or operating system. A developer also doesn’t need to compile a program on each platform like C++, because the source code is compiled into optimized Java instructions, known as bytecode. Then, a specialized execu- tion component known as the Java Virtual Machine (JVM) takes that bytecode and runs it on any platform with the JVM installed. The JVM is probably the reason why Java hasn’t faded away and only grows in popularity as devices and platforms become more diverse and powerful.
Note: The keyword, native, allows for native code to be integrated into Java applications to optimize certain features for target platforms. Overuse of native code will nega- tively affect the default portability of a Java application.
Lesson 1 11
Self-Check 1
At the end of each section of Programming in Java, you’ll be asked to pause and check your understanding of what you’ve just read by completing a “Self-Check” exercise. Answering these questions will help you review what you’ve studied so far. Please complete Self- Check 1 now.
1. What is the fundamental difference between a procedural programming language and an OOP language?
__________________________________________________________
2. What does the slogan “write once, run anywhere” mean for Java?
__________________________________________________________
Check your answers with those on page 201.
Programming in Java12
NOTES
Lesson 1 13
ASSIGNMENT 2: INSTALL THE JAVA RUNTIME ENVIRONMENT Read Assignment 2 in this study guide. Then, read pages 10–11 in your textbook.
The Java Runtime Environment (JRE) is a composite of the JVM, runtime commands and applications, and essential class libraries. The runtime commands include java and javaw for running stand-alone programs, Java Web Start to deploy applications through a browser, and Java Plug-in to run applets within a browser. Essential class libraries include classes for input/output (I/O), networking, database connections, and user interface design.
Oracle offers three different flavors for the Java Runtime Environment:
■ Standard Edition (SE)
■ Enterprise Edition (EE)
■ Micro Edition (ME)
Java EE provides additional support for servlets, Java Server Pages (JSP), Java Server Faces (JSF), Enterprise Java Beans (EJBs), and other technologies associated with business applications. Think of Java SE as the client-side runtime, while Java EE provides an additional framework for server-side applications. Java ME is a configurable subset of the Java SE for supporting small devices such as printers, mobile phones, and smart cards. Java ME doesn’t contain all class libraries found in SE, but does include Java for Mobile Devices, Java Technology for Embedded, Java TV, and Java Card.
Java Development Kit
To run a Java application, only the JRE is required. To develop a Java application, you also need the Java Development Kit (JDK). The JDK includes all components of the JRE, the com- piler javac, and other developer tools. These tools provide automated documentation with JavaDoc, a compression
Note: Web Start appli- cations and applets are now known as rich internet applications (RIAs) by Oracle.
Programming in Java14
formatter known as Java Archive (JAR), and even its own relational database called Java DB. The JDK is also known as the Java Software Development Kit (SDK), so don’t let the name conflict confuse you. These two terms are synonymous and used interchangeably in most documentation.
When downloading the JDK, you can choose to install the JDK only or bundled with other Java technologies such as JavaFX or Java EE tools. The textbook uses the JDK only, but for this course, you’ll download and install the JDK bundled with the NetBeans Integrated Development Environment (IDE).
Activity 1: Install the JDK 7 with NetBeans Bundle
1. Download the JDK 7 with NetBeans Bundle from the Oracle Java SE Download page (Figure1). The current download URL is http://www.oracle.com/technetwork/ java/javase/downloads/jdk-7-netbeans-download- 432126.html
a. On the Web page, choose the Accept License Agreement radio button.
b. Click on the file required for your platform. For most students, this would be the link labeled Windows x86.
c. Choose to save the file, so that you can re-run it if necessary.
d. Once the download is complete, run the file. If you’re prompted to allow the program to make changes to your computer, click the Yes button.
2. Navigate through the Java SE Development Kit and NetBeans IDE Installer wizard.
a. Click the Next button.
b. On the JUnit License Agreement page, choose I accept the terms in the license agreement. Install JUnit.
Lesson 1 15
c. You can change the JDK installation location if you would like. Click the Next button.
d. You can change the NetBeans IDE and JDK for the NetBeans IDE installation locations if you like. Click the Next button.
e. Verify your configuration settings and then click the Install button.
f. The installation will take several minutes. Click the Finish button when it completes.
If you have any problems during the installation, please let your instructor know.
FIGURE 1—NetBeans Download Page
Programming in Java16
NetBeans Projects
NetBeans is intended for developing and deploying Java applications with many moving parts. To simplify manage- ment, code is organized into projects and further subdivided into packages. A project is a complete application, while each related group of components in that project is a package.
NetBeans includes the following types of projects:
Java Application—Standard stand-alone application that’s run using the java command. To simplify compilation, an auto-generated build script handles all source code files.
JavaFX Application—A stand-alone application with JavaFX enabled for a rich graphical user interface (GUI).
Java Class Library—Reusable code library with no user interface.
NetBeans Module—Plug-in for the IDE itself. Since NetBeans is a Java application, you can use Java to create plug-ins for it.
Activity 2: Create Your First NetBeans Project
1. To launch NetBeans, click on the Start Menu and click the All Programs section. Choose NetBeans IDE 7.2 in the NetBeans folder.
2. In the File menu, choose New Project.
3. In the New Project wizard, choose the Java category and Java Application project (Figure 2).
4. Click the Next button.
5. Type the name FirstJavaApp in the Project Name text box at the top. Leave all other default settings (Figure 3).
6. Click the Finish button. It will take several seconds for the new project to be created and saved.
Lesson 1 17
FIGURE 2—New Project
Figure 3—New Java Application Dialog
Programming in Java18
Self-Check 2
1. What is the primary difference between the Java SE and ME runtime environments?
__________________________________________________________
2. Why do you need to install the JDK to write Java applications? Is the JDK required to run Java applications?
__________________________________________________________
Check your answers with those on page 201.
Lesson 1 19
ASSIGNMENT 3: WRITE, COMPILE, AND EXECUTE JAVA PROGRAMS Read Assignment 3 in this study guide. Then read pages 12–30 in your textbook.
As described on page 12 in the textbook, the basic development process is three steps: enter, compile, and run. In real-world development, you would first define what the application will do and design the class structure and user interface prototypes.
Another important step is missing after compiling and running a program: debugging! The compiler will catch syntax errors, but semantic errors won’t be obvious until running the appli- cation. Rarely will an application work perfectly as written, especially when you’re writing in a new programming language. Don’t be discouraged; making mistakes and learning how to debug them is an integral part of becoming familiar with a new language.
On page 13, the textbook describes how to compile and execute a Java program using the command line. Because you’ll be using NetBeans, the compile and execute steps are combined into one. To run a Java application, simply click the Run Project button (F6). The term building refers to the process of compiling all classes within a project. Although NetBeans automates the process somewhat, it’s important to remember that Java source code files have the extension .java, and compiled bytecode files have the extension .class. Also, mul- tiple .class files can be combined into executable archive files with the extension .jar.
Programming in Java20
The main() Method
In Java, a class is the primary container for code. Because most applications consist of multiple classes, the class that contains the main() method will be loaded first. The main() method is the initial entry point, where JVM will start execution. The main() method is declared in a class as follows:
class SomeClass { public static void main ( String[] args ) {
//Starting code goes here }
}
The code in bold is required by the JVM to see the main() method. The public keyword ensures the main() method is visible to the JVM, while the static keyword allows the JVM to call the method without first creating a class object. The void keyword indicates that there’s no return value. The argument String[] args allows you to send arguments from the command line when running an application. The variable args can be named anything else, but common convention is args. The following is an example of sending arguments:
java JavaApp1 “Argument 1” arg2 3
All arguments are treated as String objects (more about that in the next lesson). The textbook describes command-line arguments in more detail on pages 165–166 of Chapter 5. With NetBeans, your applications won’t use command-line arguments, because they’ll be launched through the IDE, not via the command line.
Java Syntax and Common Coding Conventions
Like C and C++, Java is case-sensitive and uses the semicolon ; to terminate lines of code. Case-sensitivity can cause some frustration to programmers who are familiar with more lenient languages like Visual Basic. Don’t think of it as an arbitrary convention—think of it as a way for the compiler to encourage good programming practices.
Note: Your textbook uses the argument String args[] instead of String[] args, but either order is allowed. String[] args is the pre- ferred convention.
Lesson 1 21
Code Blocks and Comments
Java uses curly brackets { } to enclose blocks of code and uses square brackets [ ] to define and access arrays (more about that in the next lesson). Pages 24–26 in the textbook go into more depth about how to create blocks of code and good indentation practices when doing so.
The characters // specify an inline comment, while /* and */ are used for block comments. Developers use comments to highlight important or complex algorithms, to provide book- marks for future reference, or to remove code that may contain errors during debugging. The compiler never reads comments.
int i = 0; //This code initializes an integer to the default value 0.
/*
* This is a longer comment
* set off from the code
* in multiple lines.
*/
Note: You can use the Toggle Comment option from the Source menu or the keyboard shortcut CTRL+/ in NetBeans to hide code during debugging.
Programming in Java22
There are also special comments using the characters /** and */ for detailed documentation comments using JavaDoc. The example below describes the loadImage method:
/** * Returns an {@link Image} object based on an
absolution {@link URL} * and filename {@link String}. * This method returns null if no compatible image
files exist. * @param url an absolute URL * @param name the image filename * @return An Image object * @see Image
*/ public Image loadImage(URL url, String name) {
//Imagine some code here }
JavaDoc can then pull out the comments into HTML, XML, or any other standard documentation format to share them with other developers. JavaDoc will even generate missing com- ments for parameters, return types, and other details. For more details on JavaDoc, you can visit the Oracle Website at http://docs.oracle.com/javase/7/docs/technotes/guides/ javadoc/.
Identifiers
When defining a class, method, variable, or custom data type, you must follow Java naming rules. The first character of an identifier can be a letter, an underscore _, or, a dollar sign $. All subsequent characters can also include digits. As in other languages, Java keywords are those that have special mean- ing and aren’t allowed when you define your own identifiers. See page 29 in the textbook for the complete list of Java key- words and examples of allowable identifiers.
Lesson 1 23
When following syntax rules, you should also consider com- mon programming conventions, especially those implemented in the language. There are two casing schemes used in most programming languages: camel and Pascal. Camel casing keeps the first letter of the name lowercase, but then uses uppercase for the first letter of each logical word or abbrevia- tion. A competing standard is known as Pascal casing, where even the first letter is uppercase. In Java, variables, methods, and package names use camel casing, whereas Pascal casing is used for class names and custom data types. This conven- tion makes it easier to eyeball whether something is a class or method without combing through lengthy documentation.
Cameo of Two Data Types and Control Statements
Textbook pages 16–24 briefly mention two numerical data types, and the control statements if and for. The data type int represents whole numbers, while double represents frac- tional values. The if statement executes code only once when a condition is met, while a for statement executes code repeatedly if the condition is met. Although you’ve been exposed to these constructs before in other languages, you’ll revisit this topic within the larger context of program control in the next lesson and further along in the textbook.
Brief Tour of the NetBeans IDE
Similar to other development environments, the NetBeans IDE uses toolbars, panels, and windows to provide access to information and tools on the same screen (Figure 4). The amount of information can seem overwhelming at first, but over time, you’ll value having it at your fingertips.
Programming in Java24
Panels
For projects in this course, you need to be concerned only with the following panels:
Projects. The Projects panel contains the logical structure of all of your files associated with each NetBeans project. You can add files to your project using the File menu or by right- clicking in the Projects panel.
Files. The Files panel contains the physical structure of all files associated with each NetBeans project. You can open documents by double-clicking in the Solution Explorer panel or using the File menu.
Documents. The Documents tabbed panel contains all source code files opened in the IDE. A bolded file name in the tab indicates whether a file has been modified since it was last saved.
Navigator. The Navigator contains a logical breakdown of the current document. Each method and field is displayed and can be double-clicked to go directly to that member.
Output. The Output displays compiler information and out- put for command-line applications with no GUI. You can also used it for standard keyboard input.
Figure 4—NetBeans IDE Window
Lesson 1 25
Main Toolbar
The main toolbar in NetBeans is broken into three groups (Figure 5). The first group is used for file operations, such as creating new files and folders, opening projects, and saving all open files. The second group is used for performing undo and redo edit operations. The last group contains buttons for building, cleaning, and then re-building, executing, and debugging projects. The green triangle button and its key- board shortcut F6 builds a project and executes the bytecode.
Activity 3: Enter, Compile, and Run
You’ll enter, compile, and run a simple Java application using NetBeans. Be sure to read pages 12–28 in the textbook carefully before attempting this activity.
1. If you’ve closed out of the FirstJavaApp project and NetBeans, then launch NetBeans. (See Step 1 in Activity 2).
2. The FirstJavaApp.java file should be open in Documents. If not, double-click the FirstJavaApp.java file in Projects. You should see the following default code provided:
/* * To change this template, choose Tools |
Templates * and open the template in the editor. */
package firstjavaapp;
/** * * @author jhester */
public class FirstJavaApp {
Figure 5—NetBeans Main Toolbar
Programming in Java26
/** * @param args the command line arguments */
public static void main(String[] args) { // TODO code application logic here
} }
3. Select the comment //TODO code application logic here and replace it with the following code:
System.out.println(“Welcome to the World of Java!”);
4. Build and run the project by clicking the Run Project button in the main toolbar or using the F6 keyboard shortcut.
5. The Output panel should display the following result:
run: Welcome to the World of Java! BUILD SUCCESSFUL (total time: 1 second)
In the next part, you’ll make an intentional syntax error and observe how NetBeans handles it.
6. In the main() method, add the following line of code:
This isn’t valid syntax;
Notice how the NetBeans editor underscores the code with a red squiggly line. NetBeans is warning you that this part of the code will fail compilation.
7. Try to build and run the project anyway. Click the Run Project button in the main toolbar or use the F6 keyboard shortcut.
8. NetBeans should display the warning in Figure 6.
9. Click the Run Anyway button. The Output panel should dis- play an error message in red.
Figure 6—Compilation Error
Lesson 1 27
In the last part, you’ll make an intentional semantic error that won’t be detected until after the code is executed. This code uses the for loop introduced on page 23 of the textbook.
10. Select the error-prone code This isn’t valid syntax; and replace it with the following code:
/* * This code will behave normally at first, * but then grow too big and become large * negative values. */
for (int i = Integer.MAX_VALUE - 10000; ; i++ ) {
System.out.println(“i: “ + i); }
11. Run and build the project. Notice when the numerical value gets too large for the int data type, the number becomes negative. Because there’s no exit condition specified in the for statement, the code will run in an infinite loop.
12. In the Output panel, click the red stop button to end execution.
Finally, you’ll correct the error and run the code again. The process of running your code and verifying output is debug- ging. The more time you spend on designing and debugging, the less time you’ll spend on programming frustrations.
13. Modify the code in the for statement to stop once i becomes negative as follows:
for (int i = Integer.MAX_VALUE - 10000; i > -1; i++ ) {
14. Run and build the project. Notice how execution ends before the max value is exceeded.
Programming in Java28
Self-Check 3
1. What is the extension of a source code file and which command do you use to compile it?
__________________________________________________________
2. What is the extension of a bytecode file and which command do you use to run it?
__________________________________________________________
Check your answers with those on page 201.
29
G ra
d e
d P
ro je
c t
G ra
d e
d P
ro je
c t
OVERVIEW
You’re ready to work on your first Java application. This proj- ect will assess your understanding of writing, compiling, and running a Java program.
Make sure that you follow all directions completely and verify your results before submitting the project. Remember to include all required components in your solution or you won’t receive full credit.
Your Project
For your first project, you’ll create a simple number guessing game. The game will use a for statement to ask for three guesses and an if statement to determine if the answer is right.
Instructions
1. In NetBeans, create a new Java Application project named NumberGuess. Review Activity 2 for details.
2. In the main() method, add the code to generate a random number:
Graded Project 130
int randNum = 0, guessNum = 0; //Generates a random number from 1 to 10 randNum = new java.util.Random().nextInt(10) + 1; System.out.println(“I am thinking of a number from 1 to 10”);
3. Using a for loop, ask for three guesses. See pages 23–24 in the textbook for more details. You can use the following code to ask for a guess:
System.out.print(“Guess? “); //Wraps the default input in a simple parser called Scanner java.util.Scanner scan = new java.util.Scanner(System.in); guessNum = scan.nextInt(); //Reads the next command-line int System.out.println(“You guessed “ + guessNum);
4. Using an if statement in the for block, determine whether randNum and guessNum are equal. See pages 21–23 for in the textbook for more details. You can use the following code if randNum and guessNum are equal:
System.out.println(“You guessed it!”); break;
5. When you’re finished, the contents of the main() method should resemble the following:
int randNum = 0, guessNum = 0; //Generates a random number from 1 to 10 randNum = new java.util.Random().nextInt(10) + 1; System.out.println(“I am thinking of random number from 1 to 10”); for (/* Figure this part out yourself */) {
System.out.print(“Guess? “); java.util.Scanner scan = new
java.util.Scanner(System.in); guessNum = scan.nextInt(); System.out.println(“You guessed “ +
guessNum); if (/* Figure this part out yourself */) {
System.out.println(“You guessed it!”); break;
} }
Note: The input/output code will be explained in the last lesson. Don’t worry about under- standing all of it now.
Note: The break state- ment will be explained in the next lesson.
Graded Project 1 31
6. Compile and run the project to ensure it works as expected. To type input, make sure you click in the Output panel; otherwise, you’ll modify code.
Submission Guidelines
To submit your project, you must provide the following two files:
■ NumberGuess.java
■ NumberGuess.class
To find these files within NetBeans, go to the NumberGuess project folder. To determine this folder, right-click on NumberGuess project in the Projects panel. Copy the value for the Project Folder textbox using the keyboard shortcut CTRL+C. In Windows Explorer, paste the project folder path and hit the ENTER key. Copy both the NumberGuess.java file from the src\numberguess folder and the NumberGuess.class file from the build\numberguess folder to your desktop or any other temporary location.
Follow this procedure to submit your project online:
1. Log on to the Penn Foster website and go to My Courses.
2. Click Take Exam next to the lesson you’re working on.
3. Attach your files as follows:
a. Click on the Browse box.
b. Locate the file you wish to attach.
c. Double-click on the file.
d. Click Upload File.
e. Since you have more than one file to attach, click on the Browse box again, and repeat steps b, c, and d for each file.
4. Enter your e-mail address in the box provided. (Note: This information is required for online submissions.)
5. If you wish to tell your instructor anything specific regarding this assignment, enter it in the Message box.
6. Click Submit File.
Graded Project 132
Grading Criteria
Your instructor will use the following guidelines to grade your project.
The source code file includes the provided code: 20 points
The for statement loops only three times: 30 points
The if statement checks for equality between the required variables: 30 points
Both source and compiled code files are included: 20 points
TOTAL 100 points
33
L e
s s
o n
2 L
e s
s o
n 2
Data Types and Program Control
INTRODUCTION
As with all languages, you’ll need to learn the basics of how to store and perform operations on data and control applica- tion flow. This lesson will introduce you to using data types, operators, and expressions and handling program flow using control statements and blocks in Java. In addition, you’ll learn about how to logically group values and statements using arrays and methods, respectively.
OBJECTIVES
When you complete this lesson, you’ll be able to
■ Declare variables for values and choose the appropriate primitive data type
■ Use literal values, typecasting, and standard operators
■ Use methods associated with String objects
■ Explain how different expressions are evaluated
■ Define application logic using appropriate control statements
■ Define and use methods
■ Declare and use arrays to handle multiple related values
■ Discuss multidimensional arrays
■ Handle runtime exceptions
Programming in Java34
ASSIGNMENT 4: USE DATA TYPES, VARIABLES, AND OPERATORS Read Assignment 4 in this study guide. Then read Chapter 2, as well as pages 158–164 and 166–176 in your textbook.
In Assignment 4, you’ll be introduced to how to use variables to perform operations. Be sure to complete the Try This activ- ities in Chapter 2. They’ll acquaint you with any unfamiliar data types in the lesson. The selected pages in Chapter 5 introduce how strings are used in Java and some bitwise arithmetic operations.
Primitive Data Types
As you may remember from the previous lesson, all programming languages rely on data to perform their work. Each individual piece of data (known as a datum) can represent different things and may require different storage considerations. Water measurement will require more precision than the number of beans, for example. This data is very different than determin- ing whether the water is boiling. The water is either boiling or isn’t boiling; there’s no in-between value.
The built-in data types in Java are known as primitive types. Their storage model is remarkably simple compared to objects. The value for a primitive type has a fixed size and is stored on the default memory stack. Whether an int type stores the number 4 or 4,000,000, an int will always be 16 bits (2 bytes) in size. If two int types have the same value, they’ll still be stored separately in memory. Primitive types are both fixed in size and unique.
In terms of complexity and storage, Boolean is the simplest primitive. The only literal values valid for a Boolean are true and false. Storage is a single bit that is either 0 or 1.
For numeric values, you can choose from integer or floating- point data types. In Java, all numbers are signed, meaning that a sign bit is required for every number to indicate whether it’s positive or negative. Integers are whole numbers without fractional amounts, while floating-point numbers support decimal points. Floating-point numbers store only
Lesson 2 35
the significant digits of numbers, ignoring leading and trailing zeroes, and use a base and exponent to represent the num- ber’s magnitude. The number of significant digits is known as its precision, while the magnitude is known as its scale. For example, the value 15,050,000 is stored as 15050000 in the integer primitive int, but stored as 1.505E7 in the floating-point primitive double.
Integer primitives differ only in storage size. A byte uses 8 bits, while a long stores numbers with 64 bits or 8 bytes. The most commonly used integer primitive is int and for most programs, its size will be adequate. You’ll find a complete table of integer data types and their sizes and number ranges at the bottom of page 33 in the textbook.
The primitives float and double also differ by storage, but because they use a floating-point representation, the differ- ence is in precision and scale, not an actual value range. A float devotes 23 bits to represent the precision and 8 bits for the scale. Together with the sign bit, a float is 32 bits in size. A double is twice that size—64 bits.
The final primitive is char. This data type represents a 16-bit Unicode character (UTF-16), meaning that Java supports a majority of known languages in the world. A value for a char can be specified as an integer, literal character, or hexadeci- mal character code. Character codes are specified using the \u suffix. You can find a complete list of character codes at http://www.fileformat.info/info/charset/UTF-16/list.htm.
Variable Declaration and Scope
To reuse a value stored in memory, you must first reserve and identify it using a variable. In Java, all variables must be declared with a specified data type and name before they can be used. The data type can be a primitive or object type and the name must be a valid identifier. See the Identifiers section in the previous lesson for Java rules when using identifiers.
Programming in Java36
The following code demonstrates how to declare variables:
Notice that the second and fourth lines declare multiple vari- ables using commas. The third, fourth, and last lines also use the assignment operator (=) to declare a variable and ini- tialize its value in the same statement. In Java, variables must be initialized to a value before they’re used in other statements. The last line uses the final keyword to declare a constant. Constants can be used like variables, but they must be initialized when declared and their values can’t be modified after their assignment.
Variables don’t persist forever; they have a limited lifetime, known as scope. Scope is fairly straightforward: a variable is available only within the code block in which it’s declared. Although the same identifier can’t reference different values in the same scope, identifiers at different levels of scope can have the same name. This can cause some serious confusion, so you should avoid using the same name for variables at different scopes.
The following simplified code demonstrates scoping:
{ int x = 10; { //x is available here } } //x is out of scope here int x = 10; //this is x at a different scope
Pages 43–46 in the textbook describe scoping issues in more depth.
int num; //One uninitialized integer double num1, num2, num3; //Three uninitialized floating-point short num4 = 1000; //One initialized integer float num5, num6 = 10; //One initialized and other not final char SPECIAL_CHAR = ‘Y’; //Constant value that can’t be changed
Lesson 2 37
Using Literal Values
Unlike variables, literal values are used once and then discarded. Like most languages, Java has some conventions for writing literal values in code. Characters use single quotes while multicharacter strings use double quotes. Whole numbers are treated as int, byte, or short (depending on the literal size), while numbers with decimal points are treated as double types. If you want Java to treat whole numbers as long, then you can use the suffixes L in the literal for long. If you want Java to treat a number with a decimal point as a float, then use the suffix f. This is the one situation where Java isn’t case-sensitive. Oracle recommends using an uppercase suffix for long and lowercase suffix for float.
The following are some literals with suffixes:
long num1 = 943543511234533145L; //Number was too big for int, so must use suffix
float num2 = 453232234.52124f; //Loss of precision error if suffix was not used
By default, local variables aren’t set to a value. However, fields declared at the class level are set to a default value automatically. Table 1 lists the default values for data types when declared at the class level. Notice that all reference types or objects default to the value null. Think of null as an empty variable with no reference. The next lesson will pick up this topic again when discussing reference types.
Java 7 also supports other means of formatting and repre- senting literal numbers. Although the comma can’t be used for grouping digits in a number, the underscore character is supported. The underscore can be placed only between digits and can’t be at the end or beginning of a number. The follow- ing code demonstrates using the underscore in a literal number:
int largeNumber = 36_997_000_145;
Although the default representation for numbers is traditional decimal notation, you can specify literals using scientific notation, hexadecimal, or binary. Scientific notation is sup- ported only for the floating point types float and double, but can use an uppercase or lowercase E to indicate the expo- nent. Hexadecimal requires the prefix 0x, while the prefix 0b
Programming in Java38
indicates binary. Be aware that these alternative representa- tions are provided for convenience, but aren’t stored any differently than other numerical values.
The following are some literals specified in other notations:
double d1 = 5_100_000;
double d2 = 5.1E6; //Same value as d1 in scientific notation
byte b1 = 127;
byte b2 = 0b0111_1111; //Same value as b1 in binary
byte b3 = 0x7F; //Same value as b1 and b2 in hexa- decimal
Type Casting
Normally, Java will handle conversions between primitive types automatically. For example, assigning an int value to a double is an automatic conversion that you need not worry about it. But you’ll run into situations where there’s a conflict between data types. Take the following example:
int i = 256;
byte b = i;
Data Type Default
Boolean False
byte, short, int 0
long 0L
float 0.0f
double 0.0
char ‘\u0000’
Object Null
Table 1—Data Type defaults
Lesson 2 39
The assignment of a variable to another variable isn’t at issue, because this is common. Assigning a variable to another sim- ply copies the original value and assigns it to the second variable. The conflict isn’t in the assignment, but the value itself. The value 256 falls within the range of legal values for int, but well outside the valid range for byte. A byte can’t be more than 127. Serious consequences will result when trying to push too large a value into a smaller space. In Activity 4, you’ll explore these consequences firsthand.
In order to accept the conversion operation, you need to use explicit conversion known as casting. Casting syntax specifies the desired data type in parentheses on the right side of the assignment operation. Using casting, the example can now be compiled with the following modification:
int i = 256;
byte b = (byte) i;
In the next lesson, you’ll also use casting to perform reference type conversions as well.
Common Operators
An expression is a group of data that must be calculated at runtime. Expressions can contain literal values, variables, constants, and/or methods. Operators are special symbols that affect one or more values within an expression. The val- ues that are provided as input to an operator are known as operands. Determining the overall value for an expression is known as evaluation.
As the table on page 46 in the textbook demonstrates, Java provides standard arithmetic operators required for numeric expressions.
Note: All operators in Java are dependent on the operands you provide, especially the case when using the division operator with two integers. The result will not be a fractional amount, but an unrounded integer. You’ll need to use casting to get the decimal value. Instead of using 4 / 5, use (double) (4 / 5).
There are also single-argument operators, known as unary operators. Table 2 describes the unary operators.
Programming in Java40
As indicated by the increment and decrement operators ++ and – –, shorthand arithmetic assignment is supported by Java. To perform other arithmetic operations like division and multiplication, you would use the arithmetic operator and assignment operator together. For example, to double the variable x, you could use the expression x *= 2. Actually, the following statements are equivalent:
i++;
i += 1;
i = i + 1;
Numeric expressions must evaluate to a number like int or double, while conditional expressions must evaluate to a boolean. The two tables on page 48 in the textbook list the relational and logical operators available in Java. Note that = is used for assignment and == tests equality. Another impor- tant difference is between the default operators & and |, and the short-circuit operators && and ||. If the first operand is false when using the && operator or true when using the || operator, then the second part isn’t evaluated, because the hole expression will evaluate to false or true, respectively. Such behavior reduces computation time, but can create some unexpected results if you don’t know about it.
Unary Operator Description Code Example
+ Makes a number positive(default value) int i = +286;
– Makes a number negative float f = –120.7;
~ Reverses each binary bit of a number byte b = ~0b011; //Becomes 100
++ Increments a variable by 1 i++;
– – Decrements a variable by 1 x– – ;
! Reverses a boolean value boolean b1 = false; boolean b2 = !b1;
Table 2—Unary Operators
Lesson 2 41
Operator Precedence
Normally, operations are performed in order from left to right. Some operations have higher priority than others and are eval- uated first. This is known as operator precedence. You’ve seen this in many arithmetic operations before. Take the following example:
6 + 10 / 2 – 4
Without operator precedence, you would go from left to right, adding 6 to 10, then dividing it by 2, and finally subtracting 4. The result of 4 is incorrect, because multiplication and divi- sion occur before addition and subtraction. Using operator precedence, you should first divide 10 by 2, then add 6, sub- tract 4, and get the result of 7. Java is the same way, but there are more than arithmetic operations to consider! Table 2-3 on page 56 of the textbook lists precedence from highest to lowest. As in arithmetic, you can use the parentheses to perform operations out of their normal order.
Also confusing is the placement of ++ and – – operators. The following two expressions will increment x by 1, but will perform the operation at different times:
++x //Prefix increment
x++ //Postfix increment
In the first expression, x is incremented immediately and the new value for x will be used for any other operations. In the second expression, x is incremented later and the current value for x will be used for other expressions. Prefix opera- tions occur before evaluation, while postfix operations occur after evaluation. In the next activity, you’ll use postfix and prefix operations in expressions.
Activity 4: Using Operators in Expressions
1. Launch NetBeans if it’s not already open. To launch NetBeans, click on the Start Menu and click the All Programs section. Choose NetBeans IDE 7.2 in the NetBeans folder.
Programming in Java42
2. Create a new Java project named Lesson2Activity4. To create a new Java project, follow these steps:
a. In the File menu, choose New Project. In the New Project wizard, choose the Java category and Java Application project.
b. Click the Next button.
c. Type the name Lesson2Activity4 in the Project Name text box at the top. Leave all other default set- tings.
d. Click the Finish button. It will take several seconds for the new project to be created and saved.
3. Select the comment //TODO code application logic here and replace it with the following code:
//Activity 4 byte b1 = 0b0111_1111; int i1 = 127, i2 = -1; boolean isb1i1Equal = b1 == i1; boolean isb1i2Equal = b1 == i2;
System.out.println(“Is b1 equal to i1? “ + isb1i1Equal); System.out.println(“Is b1 equal to i2? “ + isb1i2Equal);
4. Before you run this code, take time to consider what you think the output will be.
5. Build and run the project by clicking the Run Project button in the main toolbar or using the F6 keyboard shortcut.
6. Remember that literals that begin with the 0b prefix are using a binary representation. Did the output meet your expectations?
7. Modify the byte declaration line as follows:
byte b1 = 0b1111_1111;
Lesson 2 43
8. Notice there’s a compilation error indicated by the red squiggly line under the code. Move your cursor over the highlighted statement. What does “possible loss of preci- sion” mean?
9. To make this code compile, we need to explicitly cast the value to a byte. Modify the byte declaration line as fol- lows:
byte b1 = (byte) 0b1111_1111;
10. Build and run the project again. Why is the result different?
11. Under the previous code, add the following code:
double result1 = 10.2 - 5 * 10 + i1++; double result2 = (10.2 - 5) * 10 + ++i1;
System.out.println(“result1 = “ + result1); System.out.println(“result2 = “ + result2);
12. Before you run the code, take time to consider what you think the output will be.
13. Build and run the project by clicking the Run Project button in the main toolbar or using the F6 keyboard shortcut.
14. Remember order precedence and the difference between the prefix and postfix increment operators. Also, notice that i1 starts as 127 and then is incremented to 128 after result1. Did the output meet your expectations?
You’ll use this same project in Activity 5, so you can keep it open.
Note: Remember that a byte can’t be more than 127 positive, but you tried to push into that small size the value 255. Don’t forget that one bit is reserved for its sign.
Programming in Java44
The String Object
In Java, variable-length text is stored in a specialized object known as String. String literals are enclosed using double quotes, rather than the single quotes used by char. Table 2-2 on page 40 lists some common escape characters you can use in String literals for spacing and other special charac- ters.
Because a String is an object, it has methods you can use to manipulate it. Page 160 in the textbook lists some common String methods you’ll use. Like arrays, Strings use zero-based indexes, so the first character is at position 0, not 1. Also, notice that you use the equals method to see if two String values have the same characters, not the equals operator ==. The most common operation you’ll perform with a String is concatenation. Concatenation is combining Strings using the addition operator +.
String values are immutable, meaning they can’t be modified after being initialized. In other words, a String value is actually read-only. Take the following code:
String name = “Joshua, “; name += “welcome to”; name += “ Java”; name += “.”;
Although only the name variable is declared and used, there are technically four String objects stored in memory. The concatenation is actually creating a new String object, rather than modifying the existing one. If the String values are lengthy, then you should consider using the StringBuilder class instead.
The StringBuilder class limits the number of String objects and provides additional manipulation methods. When you’re done using the StringBuilder class, you need only invoke the toString() method to get the underlying String object. You can learn more about the StringBuilder class by visiting the Oracle website at http://docs.oracle.com/javase/tutorial/ java/data/buffers.html.
Lesson 2 45
Activity 5: Perform String Operations
1. Launch NetBeans and open the Lesson2Activity4 project if you’ve closed out of the NetBeans.
2. The Lesson2Activity4.java file should be open in Documents. If not, then double-click the file in the Projects panel.
3. So that you can keep the code used in Activity 4 for fur- ther reference without affecting this activity’s code, you’ll comment out the current code. To do this, highlight the current code in the main() method and then choose the Toggle Comment option from the Source menu or the keyboard shortcut CTRL+/.
4. Add the following code to the main() method:
5. Read through the code before building and running the code. Can you predict the output?
6. Build and run the project. Does it work as expected?
7. Modify the value for the msg variable and see if you can predict how the output changes.
//Activity 5 String msg = “Java is Fun to Write and Drink!”; System.out.println(msg); System.out.println(msg.toLowerCase()); System.out.println(msg.toUpperCase()); System.out.println(“Length: “ + msg.length()); System.out.println(“First char: “ + msg.charAt(0)); System.out.println(“Last char: “ + msg.charAt(msg.length()-1)); System.out.println(“First i: “ + msg.indexOf(“i”)); System.out.println(“Last i: “ + msg.lastIndexOf(“i”));
Programming in Java46
Bitwise and Shift Operations
As you may recall from earlier programming courses, all numbers and instructions are stored using a binary representation. When creating low-level classes, you may need to manipulate these representations. Java provides the bitwise and shift operators for just this purpose. Pages 166–176 in the text- book provide a thorough introduction to bitwise and shift operators if you want to learn more. Don’t feel too intimi- dated; most Java programmers use binary representations sparingly.
Lesson 2 47
Self-Check 4
1. What are primitive data types?
__________________________________________________________
2. What is the difference between integer numbers and floating-point numbers?
__________________________________________________________
3. When should you use explicit casting?
__________________________________________________________
4. What is the value of the variable result after the following statement?
double result = (5 - 10) + 15 % 7 * 10 ^ 2;
__________________________________________________________
5. What is the value of the variable charVal after the following statement?
char charVal = “Strings of Java”.toUpperCase().charAt(2);
__________________________________________________________
Check your answers with those on page 202.
Programming in Java48
ASSIGNMENT 5: EXECUTE WITH PROGRAM CONTROL STATEMENTS AND METHODS Read Assignment 5 in this study guide. Then read Chapter 3, Chapter 4 pages 110–117, Chapter 5 pages 176–177, as well as Chapter 6 pages 194–199 in your textbook.
Assignment 5 introduces the syntax for control statements and methods. Be sure to complete the Try This activities in Chapter 3. They’ll acquaint you with any unfamiliar data types in the lesson. The selected sections in Chapters 4–6 describe basic and overloaded methods, and the ? operator.
Conditional Statements
It’s not uncommon that a statement or block of statements should execute only if a specific condition is true. One of the primary mechanisms of control in Java is the if statement. The if statement can be accompanied by the else for any statement(s) that must execute if the condition isn’t true. The general syntax is as follows:
if ( conditional_expression ) { //statements that execute if true
} else { //statements that execute if false
}
The syntax shown above is the long-hand form when more than one statement must execute. You could also use the short-hand syntax if only a single statement need execute. The following code is an example:
if (msg1.equals(msg2)) System.out.println(“EQUAL”); else System.out.println(“NOT EQUAL”);
Typical of Java, there’s also a shorter syntax. If only a single value needs to be returned, then you can use the ? operator. The ? operator uses the following syntax:
conditional_expression ? value_if_true : value_if_false
Lesson 2 49
The previous example could use the ? operator as follows:
System.out.println( msg1.equals(msg2) ? “EQUAL” : “NOT EQUAL”);
Although you can use logical operators to combine conditional expressions, you may want to perform separate checks. You can use the else-if statement to do this as follows:
if (guess == number) { System.out.println(“Good job!”); } else if (guess > number - 5 && guess < number + 5) { System.out.println(“Very close!”); } else if (guess > number) { System.out.println(“Way too high!”); } else if (guess < number) { System.out.println(“Way too low!”); }
Notice that the conditional expression in the else-if state- ment is evaluated only when the condition is false in the previous if or else-if statement.
Using else-if statements can be useful for complex conditions and value ranges, but not for testing discrete values. Java provides the switch statement for those situations. The fol- lowing code demonstrates usage of the switch statement:
switch (state) { case “TX”: shippingCost = 4.59; break; case “GA”: shippingCost = 2.85; break; case “NY”: case “LA”: shippingCost = 3.65; break; default: shippingCost = 5.00; }
Programming in Java50
Note the following about this code. The variable or expression can be a byte, int, char, String, or enumeration (more about that in the next lesson). The first two case labels for TX and GA specify only one condition, but the third label for NY falls through to the fourth label for LA. Any case label that doesn’t contain a break statement will fall through. The break state- ments exit the switch statement, so that no other code in the switch block is executed. Finally, the default label is exe- cuted if there’s no match in the previous case labels.
Iterative Statements
Whereas conditional statements will execute statement(s) only once if a condition is true, iterative statements can execute multiple times while the condition is true. The two simplest iterative statements are while and do-while. The only differ- ence between the two statements is when the condition is evaluated. Because the condition in the do-while statement is evaluated at the end of each iteration, the statements in the do-while block will execute at least once.
In both the while and do-while statements, the number of iterations is dependent on the conditional expression and not necessarily on a counter. Java provides the for statement specifically for handling counters. The general syntax for the for statement is as follows:
for (initializer_statement; conditional_expres- sion; iteration_statement) {
//statements to run here }
The initializer statement runs once before the for block starts its first iteration. The conditional expression is evaluated before each iteration, while the iteration statement is executed after each iteration. The following code demonstrates using the for statement:
for (int count = 10; count >= 0; count—) { System.out.print(count + “...”); }
System.out.println(“BLAST OFF!”);
Besides using a counter, you can also use the break and continue statements to control the number of iterations. The break statement will exit a code block, while the continue
Lesson 2 51
statement will skip the remaining code in the block and move onto the next iteration. As you saw for the switch statement, the break statement can be unlabeled to exit out of the innermost code block. You can also create labels and specify which code block to exit as follows:
outer: for (int x = 0; x < 100; x++) { inner: while (!isFound) { if (x == codeValue ) { System.out.println(“FOUND IT!”); break outer; } } }
Activity 6: Create a Simple Countdown
In this activity, you’ll use nested loops with a continue statement.
1. Create a new Java Application project named Lesson2Activity6. Review steps 1 and 2 of Activity 4 if you need help on performing this action.
2. Select the comment //TODO code application logic here and replace it with the following code:
char promptChar = ‘\u0000’; //null character //Remember this line from the first graded project? java.util.Scanner scan = new java.util.Scanner(System.in); int counter = 100, block = 10; //Total count and block
do { for (int i = block; i > 0; i— ) { System.out.print(counter + “...”); counter—; } System.out.print(“\nContinue countdown?(y/n): “); promptChar = (char) scan.next().charAt(0); } while (promptChar != ‘n’);
Programming in Java52
3. Before you run the code, take time to consider what you think the output will be. The code will count from 100 in decrements of 10, until the n character is pressed.
4. Build and run the project by clicking the Run Project button in the main toolbar or using the F6 keyboard shortcut. Remember: Click in the Output panel to type input. You have to type in a character other than n and hit the ENTER key to continue. Type n and hit the ENTER key to stop the application.
5. Think about how you could modify this code to print only even numbers in the countdown. Hint: The modulus operator % is commonly used to find even and odd numbers.
6. Replace the code in the for block with the following:
if (counter— % 2 != 0) continue; System.out.print(counter + “...”);
7. Build and run the project. Does it work as expected?
8. Notice that every tenth value is omitted. This is because the counter variable is now decremented at the beginning of each iteration. It would be easier if the for statement could handle both variables i and counter. Luckily, for loops can have multiple expressions in the iteration statement!
9. Modify the for block as follows:
for (int i = block; i > 0; i—, counter— ) { if (counter % 2 != 0) continue; System.out.print(counter + “...”); }
10. Build and run the project. It should now work as expected. How would you modify the code to exit before reaching 50? Hint: You could use the break statement.
You’ll use this same project in Activity 7, so you can keep it open.
Lesson 2 53
Declaring Methods
Methods are useful in hiding complexity and reusing common code. Two methods you’ve been using so far are main() and println(). The main() method is where you placed code to run when the application starts, while println() writes output to the command line. You also learned about methods used with String objects, such as toUpperCase() and charAt(). Some of these methods accept input data known as arguments and when they finish, send back output known as a return value.
To declare your own methods, you should use the following syntax:
return_type MethodName (list_of_parameter_types) { //definition here }
The return type specifies what data type the method will return or the keyword void if no value is returned. To return a value in a method, you use the return statement. Java is very strict about return values—if the method specifies a return type, then all code paths in the method must return that data type or compilation will fail. You can also specify a return statement with no value to exit a method prematurely.
The parameter list is comma-delimited and order-dependent. When invoking a method, the Java runtime determines the values for the parameters based on the order of arguments.
Take the following method:
double drink(double sipAmount, double totalSize ) {
return totalSize - sipAmount; }
Because this method specifies two double parameters, you must provide two double arguments to invoke it. You don’t need to handle the return value, but the order in which you place the arguments will affect the return value. If you invoke the drink() method with drink(10, 20), then the argument 10 will be the value for the sipAmount parameter, 20 will be the value for the totalSize variable, and the return value will be 2.0.
Programming in Java54
Java also allows a variable number of arguments, known as varargs. Unlike normal parameters, a varargs parameter is optional and can have more than one value. The following method uses the ellipse to specify a varargs parameter:
void printArgs(Object... objs) { for (int i = 0; i < objs.length; i++) { System.out.println(“Argument#” + i + “: “ +
objs[i]); } }
This should look similar to how main() method arguments were handled in the first lesson. This is because the varargs parameter is treated like an array. Arrays will be discussed in the next section.
The code printArgs(“Testing”, 5, 10.5f, ‘c’, false); will produce the following output:
Argument0: Testing
Argument1: 5
Argument2: 10.5
Argument3: c
Argument4: false
A varargs parameter can appear as the only or last parameter for a method. Otherwise, the runtime would be unable to dif- ferentiate between normal and varargs parameters.
Note: Like class variables, methods can also include modifiers such as public and static. These modifiers will appear before the return type. In the next lesson, the meaning of these modifiers will be discussed. For now, just understand that static is a required modifier when invoking a method directly from the main() method. Remember the main() method is also declared with the static keyword.
Overloading
Recall that the Java runtime determines the values for the parameters based on the order of arguments when invoking methods. The name of a method and its order of parameter data types is known as a method signature. The method
Lesson 2 55
signature is how the runtime figures out which method should be invoked. When you invoke a method named doSomething with the arguments 3, 4, 5, and 6, then the Java runtime is looking for a method with the signature doSomething(int,int,int,int). Because of automatic type conversions, other compatible signatures could also include doSomething(double,double,double,double) or even doSomething(int,double,int,double).
Why is this somewhat obvious point worth mentioning? It’s because Java supports a feature known as overloading. Overloading occurs when two or more methods have the same name, but specify a different order or data types for parameters. Overloading enables a single method name to be reused, so that it can be specialized for different situations. Take the drink() method from before. You could expand it to accept an additional argument to handle more than one con- tainer. The following code overloads the drink() method:
Again, the Java runtime knows which version of the drink() method you want based on the arguments you provide. If you provide two double arguments, then the first drink() method is invoked. If you provide that additional int argument, then this second drink() method is invoked. Pages 194–199 in Chapter 6 of the textbook provide further examples of method overloading. In the next activity, you’ll use overloaded meth- ods to modify the countdown application.
Activity 7: Create Countdown Methods
1. Open the Lesson2Activity6.java file in NetBeans.
2. Cut the following code from the main() method:
for (int i = block; i > 0; i—, counter — ) { if (counter % 2 != 0) continue; System.out.print(counter + “...”);
}
double drink(double sipAmount, double totalSize, int numContainers) { return numContainers * (totalSize - sipAmount);
}
Programming in Java56
To cut the code, highlight the code lines and use the keyboard shortcut CTRL+X. You can also right-click on the selected code and choose the Cut option from the context menu.
3. Declare the following methods in the Lesson2Activity6 class (make sure you place your cursor before the final closing curly brace):
4. Notice these are overloaded countdown methods. The first countdown method will take three arguments so that the countdown occurs in blocks and skips certain numbers. The second countdown method will work only countdown in blocks and not skip numbers. The third countdown method will simply count down without using blocks or skipping numbers. The first two count- down methods return an int, so that the program can continue the countdown after the method returns. The last countdown will keep going until it reaches 1, so it returns no value.
5. Paste the cut code into the first countdown method. You can use the keyboard shortcut CTRL+V or right-click in the method and choose the Paste option from the con- text menu. Don’t worry if the paste operation failed; you can always retype the code from step 2.
static int countdown (int counter, int block, int skip) {
} static int countdown (int counter, int block) {
} static void countdown (int counter) {
}
Lesson 2 57
6. Modify the code in the first countdown method as follows:
7. As you might imagine, the code for the second count- down method will be very similar. So why should you rewrite all of that code? The second countdown method could just call the first version, using the value of 1 for the skip argument. This is informally called piggybacking.
8. Add the following code to the second countdown method:
return countdown(counter, block, 1);
9. You can do the same thing with the third countdown method as follows:
countdown(counter, counter);
Notice that there’s no return statement, because the third countdown method doesn’t return a value. By specifying the counter argument for both the counter and block parameters, you’re allowing the countdown to go completely to 1.
10. Go back to the main() method and in the do-while block, invoke the first countdown method as follows:
counter = countdown(counter, block, 2);
11. Build and run the project. The output should match as it did at the end of Activity 6.
12. Now, replace the code and invoke the second countdown method as follows:
counter = countdown(counter, block);
13. Build and run the project. The output should now match as it did at step 4 of Activity 6.
static int countdown (int counter, int block, int skip) { for (int i = block; i > 0; i—, counter — ) { if (counter % skip != 0) continue; System.out.print(counter + “...”); } return counter; }
Programming in Java58
14. Finally, replace the code and invoke the third count- down method as follows:
countdown(counter);
15. Build and run the project. The output should now count all the way down to 1. Feel free to modify your arguments to see how the output changes.
Lesson 2 59
Self-Check 5
1. Which iterative statement executes at least once?
__________________________________________________________
2. Which iterative statement uses an explicit counter?
__________________________________________________________
3. Which two statements control iterations within an iterative code block?
__________________________________________________________
4. How many return values can a method return?
__________________________________________________________
5. How many arguments are required for varargs parameter?
__________________________________________________________
Check your answers with those on page 202.
Programming in Java60
ASSIGNMENT 6: USE ARRAYS FOR MULTIPLE VALUES Read Assignment 6 in this study guide. Then read Chapter 5, pages 136–158 in your textbook.
Assignment 6 introduces a new data type to handle multiple values. Be sure to complete the Try This activities 5-1 and 5-2 in Chapter 5 to reinforce general use of arrays. Chapter 5 also covers irregular arrays, which aren’t addressed in this assignment.
Declare Arrays
An array is a zero-based index of common elements. In Java, arrays must meet the following criteria:
1. Each element must be the same data type.
2. Its length must be set to an int value.
3. Its length is fixed and can’t be modified.
When using arrays it’s also useful to remember that the last index is always one less than its length. For example, an array with a length of 10 elements will have elements at index posi- tions 0 through 9.
An array declaration is the same as any other variable declaration, but also includes square brackets. You may remember that the main() method declares an array parameter to handle command-line arguments as follows:
public static void main(String[] args)
You can also declare an array by placing the square brackets after the variable name, but this isn’t common convention. Because arrays are objects, they must be initialized before they’re accessed. To initialize an array, you must use the new keyword and specify its length in a pair of square brackets. In the next lesson, you’ll use the new keyword for other objects as well.
Lesson 2 61
The following code declares and initializes an int array with five elements:
int[] intArray = new int[5];
Notice the data type is repeated after the new keyword. Because an array is an object, the value for each element is set to its default. In this example, each int element is set to 0.
Using Arrays
To access elements in an array, you’ll use the square brack- ets as well. The following code sets each element in the array initialized in the previous example:
intArray[0] = 1; intArray[1] = 2; intArray[2] = 3; intArray[3] = 4; intArray[4] = 5;
Of course, this code is very tedious, especially as arrays get larger in size. You already learned about a better technique. Instead of manual code repetition, you can use a cleaner algorithm to do the same thing with a for statement:
for (int i = 0; i < intArray.length; i++) { intArray[i] = i + 1; }
Notice the length field is used to retrieve the number of ele- ments in the array. If you need to initialize an array with values, you can also use another short-hand notation with curly braces. The following code declares and initializes an array with values using this notation:
String[] names = {“Joshua”, “Chelsea”, “April”, “Alisha”};
Java understands the number of elements based upon the number of provided arguments. The arguments have to match the data type of the array declaration, of course.
Programming in Java62
Enhanced For Statement
When using arrays, you can choose a special type of for state- ment known as the enhanced for. The enhanced for statement will automatically iterate across an array and retrieve each element without requiring an explicit index. The syntax for the enhanced for is as follows:
for ( data_type variable_name : array_name) { //access each element in array
}
The following code will output each value in intArray using the enhanced for statement:
for (int intElement : intArray) { System.out.println(intElement); }
The enhanced for statement makes sense only when an index is needed to access elements. If the index is required for another purpose such as modifying element values or performing a calculation, the enhanced for statement isn’t very helpful.
Activity 8: Create a Simple Calculator
1. Create a new Java Application project named Lesson2Activity8.
2. Select the comment //TODO code application logic here and replace it with the following code:
java.util.Scanner scan = new java.util.Scanner(System.in);
System.out.print(“Number of operands? “); double[] operands = new double[scan.nextInt()]; for (int i = 0; i < operands.length; i++) { System.out.print(“\nValue “ + i + “ : “); operands[i] = scan.nextDouble(); }
System.out.print(“\nOperation? “); String operation = scan.next();
Lesson 2 63
3. Before you run this code, take time to consider how you think the application will behave. This code will ask for a number of values, ask for an operation, and then return the result.
4. Build and run the project. Remember: Click in the Output panel to type input. Try doing an operation you can check easily to verify that it works. Test both operations.
5. Consider how you would add another operation such as subtraction or division. How would the for statement differ?
Multidimensional Arrays
Java also supports arrays with more than one index, which are known as multidimensional arrays. Multidimensional arrays are used to represent matrices, tables, flat and 3D shapes, and image coordinates. For each dimension in a multidimen- sional array, another pair of square brackets is required. These extra pairs of square brackets set the length of each dimen- sion during initialization and specify the other index of each dimension during access.
double result = 0; switch (operation.toUpperCase()) { case “ADD”:
result = 0; //Required for addition for (double num : operands) result += num; break;
case “MULTIPLY”: result = 1; //Required for multiplication for (double num : operands) result *= num; break;
default: System.err.println(“\nNo such operation defined.”);
} System.out.println(“\nThe result is “ + result);
Programming in Java64
The following code initializes a two-dimensional array and sets its first and last elements:
String[][] matrix = new String[4][5]; matrix[0][0] = “first”; matrix[3][4] = “last”;
The total number of elements in a multidimensional array is the product of elements in each dimension. If you access the length field from a single dimension, then it will return only the number of elements in that single dimension. For example, matrix.length will return 4, representing the number of dimensions, while matrix[0].length will return 5, indicating the number of elements in that dimension. The total number of elements for a matrix is 20, because there are 4 dimensions with 5 elements in each dimension.
Lesson 2 65
Self-Check 6
1. What are the three restrictions for arrays in Java?
__________________________________________________________
2. Which field returns the number of elements in an array?
__________________________________________________________
3. Which index value will retrieve the first element in an array?
__________________________________________________________
Check your answers with those on page 203.
Programming in Java66
ASSIGNMENT 7: EXCEPTION HANDLING Read Assignment 7 in this study guide. Then read Chapter 9 in your textbook.
Assignment 7 describes how to deal with runtime errors in code.
Runtime Exceptions
An exception is an abnormal condition that occurs while an application is running. Most often, an exception is an error, but in some cases, the exception isn’t fatal and the applica- tion can recover. When an exception occurs, it’s thrown. As a programmer, you can also throw exceptions manually.
If you don’t design an application to handle exceptions, then the operating system will have no choice but to termi- nate the application prematurely. Although you can avoid many exceptions by performing simple checks, you can’t pre- dict all exceptions. Also, some methods in Java require you to plan for exceptions in order to invoke them. These types of exceptions are known as checked and must be dealt with for the code to compile. Exception handling is the mechanism of listening for exceptions and dealing with them when they occur.
Exception classes take advantage of all object-oriented design principles. Exception objects are recoverable situations that usually are within the control of a user or programmer, whereas Error objects are system issues that aren’t recoverable and shouldn’t be handled. Both the Exception and Error class inherit core methods from the Throwable class. This means that all exceptions have a user-friendly message available from the getMessage() method and a complete path from which the exception originated with the printStackTrace() method. Java has both generalized Exception classes, such as IOException and IllegalArgumentException, and more specific Exception classes, such as FileNotFoundException and PrintException. Tables 9-2 and 9-3 on pages 315 and 316 in Chapter 9 of the textbook document the most com- mon exceptions.
Lesson 2 67
Exception Handling
There are four ways to deal with exceptions in a method:
1. Declare the exception thrown by the method (required if checked by compiler).
2. Handle the exception and continue execution.
3. Handle the exception and throw the exception again (known as re-throwing).
4. Handle the exception and throw another exception.
To declare a method throws an exception, you should use the throws keyword as in the following example:
void couldDoSomethingVeryBad() throws Exception
The throws clause on a method means that to invoke the method, the declared exception must be handled or also declared unhandled by the invoking method. To handle the exception, you should use the try/catch blocks. The try/catch blocks use the following syntax:
try { //statements that might throw an exception
} catch ( exception_types exception_variable) { //handle the exceptions
}
The catch parameter can include more than one type of exception or you can use multiple catch blocks for each type of exception. To declare multiple exceptions in the catch parameter, use the bitwise OR operator |.
If you use more than one catch block, then be careful that they’re in order of specific to general or some catch blocks may be unreachable. Every try block must have at least one accompanying catch block, but that catch block can be empty. To manually throw an exception, you should use the throw statement. There’s also an optional finally block if you need to have any code run whether or not an exception is thrown.
Programming in Java68
The following code handles any divide by zero exceptions that are thrown and throws another exception:
A simple check for num1 so that it isn’t zero is a better approach than using exception handling. In a future lesson, you’ll see better uses for exception handling when performing input/output operations.
double divide(double num1, double num2) {
double result = 0;
try {
result = num1 / num2; //num1 should not be zero
} catch (ArithmeticException ex) {
throw new IllegalArgumentException(“num2 parameter must not be 0!”);
} finally {
return result;
}
}
Lesson 2 69
Self-Check 7
1. What is an exception?
__________________________________________________________
2. Which blocks should you use to handle exceptions?
__________________________________________________________
3. How are the keywords throw and throws used in Java?
__________________________________________________________
Check your answers with those on page 203.
Programming in Java70
NOTES
71
G ra
d e
d P
ro je
c t
G ra
d e
d P
ro je
c t
Data Types and Program Control
OVERVIEW
After reading selected sections of Chapters 2, 5, and 9 in the textbook and completing Lesson 2, you’re now ready to use data types and control structures. This project will assess your understanding of using variables, constants, operators, arrays, statements, methods, and exceptions.
Make sure to follow all directions completely and verify your results before submitting the project for grading. Remember to include all required components in your solution.
Your Project
In this project, you’ll create a text-based Tic-Tac-Toe game in which each player places either an X or O mark on a nine- grid square. An X mark is known as a cross, while an O is called a nought. The winner is the first player to place their mark on three contiguous squares vertically, horizontally or diagonally across. You can read about it in more detail on Wikipedia (http://en.wikipedia.org/wiki/Tic-tac-toe).
The output of this project will be referenced in the subsequent graded projects for this course.
Graded Project72
Instructions
1. In NetBeans, create a new Java Application project named TicTacToeGame.
2. Add the following variable and constant declarations to the TicTacToeGame class:
static int[][] gameboard; static final int EMPTY = 0; static final int NOUGHT = -1; static final int CROSS = 1;
Note: The variable gameboard is a two-dimensional int array. Think of it as a table with rows and columns, where a cell can be empty (0) or contain a nought (–1) or cross (1) . The constants EMPTY, NOUGHT, and CROSS will simplify your code.
3. Add the following utility methods to the TicTacToeGame class:
static void set(int val, int row, int col) throws IllegalArgumentException { if (gameboard[row][col] == EMPTY) gameboard[row][col] = val; else throw new IllegalArgumentException(“Player already there!”); }
static void displayBoard() { for( int r = 0; r < gameboard.length; r++ ) { System.out.print(“|”); for (int c = 0; c < gameboard[r].length; c++) { switch(gameboard[r][c]) { case NOUGHT: System.out.print(“O”); break; case CROSS: System.out.print(“X”); break; default: //Empty System.out.print(“ “);
Graded Project 73
} System.out.print(“|”); } System.out.println(“\n———-\n”); } }
4. Add the following method signatures to the TicTacToeGame class:
5. Define the createBoard method.
6. Define the winOrTie method. Check first for a win with rows and columns and then diagonally. Finally, check to see if there are any empty cells without a cross or naught.
Note: Review the sections “Initializing Multidimensional Arrays” on pages 144–145 and “Iterating Over Multidimensional Arrays” on pages 156–158 for how to initialize and iterate through a multidimensional array. A player wins if all the cells in a row or column are the same mark or diagonally through the center. The players tie if all cells have a cross or nought, but no player has three marks horizontally, verti- cally, or diagonally. Return NOUGHT if nought wins, CROSS if cross wins, 0 if there’s a tie, and another value (like –2, for example) if there are empty cells on the board.
7. In the main() method, perform the following actions:
a. Create the board and initialize a turn counter, player value, and game outcome. For nought, the value is –1, while 1 is the value for cross.
b. While there’s no winner or tie, display the board and prompt for a row and column for the current player.
static void createBoard(int rows, int cols) { //Initialize the gameboard
} static boolean winOrTie() {
//Determine whether X or 0 won or there is a tie }
Graded Project74
c. Use a try/catch block to handle the exception from the set method. You can use the System.err.println method rather than the System.out.println method to output the exception. This will display the message in red.
d. Display the final board and a message on which player won or if there’s a tie.
8. When completed, the contents of the main() method should resemble the following:
createBoard(3,3); int turn = 0; int playerVal; int outcome; java.util.Scanner scan = new java.util.Scanner(System.in); do { displayBoard(); playerVal = (turn % 2 == 0)? NOUGHT : CROSS; if (playerVal == NOUGHT) System.out.println(“\n—O’s turn—”); else System.out.println(“\n—X’s turn—”); System.out.print(“Enter row and column:”); try { set(playerVal, scan.nextInt(), scan.nextInt()); } catch (Exception ex) {System.err.println(ex);} turn ++; outcome = winOrTie(); } while ( outcome == -2 ); displayBoard(); switch (outcome) { case NOUGHT: System.out.println(“O wins!”); break; case CROSS: System.out.println(“X wins!”); break; case 0: System.out.println(“Tie.”); break; }
Graded Project 75
9. Compile and run the project to ensure it works as expected. Try a few games to verify all wins and ties are correctly detected.
The application should behave as follows in the Output window:
| | | | ______ | | | | ______ | | | | ______ —O’s turn— Enter row and column:0 0 |O| | | ______ | | | | ______ | | | | ______ —X’s turn— Enter row and column:0 1 |O|X| | ______ | | | | ______ | | | | ______ —O’s turn— Enter row and column:1 1 |O|X| | ______ | |O| | ______ | | | | ______
—X’s turn— Enter row and column:2 0 |O|X| | ______ | |O| | ______ |X| | |
______ —O’s turn— Enter row and column: 2 2. |O|X| | ______ | |O| | ______ |X| |O|
O wins!
SUBMISSION GUIDELINES
To submit your project, you must provide the following two files:
■ TicTacToeGame.java
■ TicTacToeGame.class
To find these files within NetBeans, go to the TicTacToeGame project folder. To determine this folder, right-click on TicTacToeGame project in the Projects panel. Copy the value for the Project Folder textbox using the keyboard shortcut CTRL+C. In Windows Explorer, paste the project folder path and hit the ENTER key. Copy both the TicTacToeGame.java file from the src\tictactoegame folder and the TicTacToeGame.class file from the build\tictac- toegame folder to your desktop or any other temporary location.
Follow this procedure to submit your project online:
1. Log on to the Penn Foster website and go to My Courses.
2. Click Take Exam.
3. Attach your files as follows:
a. Click on the Browse box.
b. Locate the file you wish to attach.
c. Double-click on the file.
d. Click Upload File.
Graded Project76
Graded Project 77
e. Since you have more than one file to attach, click on the Browse box again, and repeat steps b, c, and d for each file.
4. Enter your e-mail address in the box provided. (Note: This information is required for online submissions.)
5. If you wish to tell your instructor anything specific regarding this assignment, enter it in the Message box.
6. Click Submit File.
Grading Criteria
Your instructor will use the following guidelines to grade your project.
The createBoard method works as required: 25 points
The winOrTie method works as required: 30 points
The application plays a standard Tic-Tac-Toe game 25 points
Both source and compiled code files are included: 20 points
TOTAL 100 points
Graded Project78
NOTES
79
L e
s s
o n
3 L
e s
s o
n 3
Object-Oriented Programming
INTRODUCTION
Because Java is an object-oriented language, learning its structures will provide a review of object-oriented program- ming (OOP). Java was built with good object-oriented design principles in mind, making it easier to do the right thing, but more restrictive than other languages you’ve learned. In this lesson, you’ll define classes, interfaces, and enumerations and revisit important OOP concepts such as inheritance and poly- morphism. You’ll also learn how to use Java’s packaging scheme and generics.
OBJECTIVES
When you complete this lesson, you’ll be able to
■ Define and instantiate classes
■ Describe reference variables and the object lifetime
■ Use inheritance and polymorphism
■ Differentiate between abstract and concrete classes
■ Use Java packages and the application programming interface (API) documentation
■ Differentiate between interfaces and classes
■ Create interfaces and enumerations
■ Discuss autoboxing and generics
Programming in Java80
ASSIGNMENT 8: CREATE OBJECTS AND CLASSES Read Assignment 8 in this study guide. Then read Chapter 4, pages 104–110 and 124–134, as well as Chapter 6 in your textbook.
Create Objects and Classes
The focus of Assignment 8 is using OOP with Java syntax. This assignment assumes you have a good grasp of general object-oriented design principles. If you need a refresher on object-oriented design, you can read the Java tutorial on the Oracle website at http://docs.oracle.com/javase/tutorial/ java/concepts/index.html. Be sure to complete the Try This activities in both Chapters 4 and 6; they’ll help to reinforce the syntax and concepts.
Object Fundamentals
As you’ve learned in previous lessons, an object is a unique representation of variable-sized data in memory. This data consists of two things: state and behavior. State describes the object, while behavior defines what that object can do. The word unique means one object is stored separately from another, even if they have the same state. In Java, state is defined by variable fields, while behavior is defined by methods.
A class is a user-defined type that describes objects. Although a class is loaded into memory like objects, a class doesn’t have a unique state or behavior. Only static fields and methods are available through a class. Any changes to the class will affect all objects based on that class, however. Think of a class as a group and objects as members of that group. A class is merely a classification for a type of object.
An important object-oriented design principle is encapsulation. Encapsulation is designing a class, so that fields are pro- tected from direct access and all interaction with an object requires methods. A method that retrieves a field’s value is known as an accessor. A mutator is a method that modifies a field’s value.
Lesson 3 81
Class Definition in Java
The following code defines the Robot class in a two-dimensional maze application:
class Robot { //fields (state) String name; int x,y; int direction; double speed; //methods (behavior) void turn(int direction) {} void move(double time) {} void move(double time, int direction) {} void setSpeed(double speed) {}
}
Note the use of the class keyword to specify the new data type. The fields are merely variables declared directly in the class body. It’s worth mentioning that the methods don’t use the static keyword as you were using in the previous lesson because the methods will affect a single object. If you invoke the move() on a Robot object, another Robot object won’t have its x and y fields change.
The process of creating an object from a class is known as instantiation. As with arrays, you need to use the new key- word to instantiate a class. You’ll use parentheses instead of square brackets, however. The following code instantiates the Robot class twice to create two Robot objects and then sets each of their fields:
Robot robo1 = new Robot(); robo1.name = “Marvin”; robo1.speed = 4.2; Robot robo2 = new Robot(); robo2.name = “Chip”; robo2.speed = 12.8; robo1.move(10); robo2.move(5);
Notice that dot notation is used to access object fields and methods. Also, notice that the robo1 and robo2 objects have separate field values and methods. When the move() method
Programming in Java82
is invoked on robo1, robo2 remains in its current state. While the move method is invoked for robo2, the state for robo1 is unaffected.
Another important point is the default state of the Robot objects. All fields will start with their default values. Because the x, y and direction fields aren’t set, their current state is 0, 0 and 0.0, respectively.
Object References
As you’ll recall from the first assignment in the previous lesson, assigning a variable to another simply copies the original value and assigns it to the second variable. The following code demonstrates this concept:
Values for primitive data types are stored on the default memory stack. The only data stored for a primitive variable is its value.
Because the size of object data isn’t fixed, objects are stored in the memory heap. The size of an object is determined when it’s instantiated, not using a size predefined by the JVM. If object data is stored in the memory heap, then what’s stored in the memory stack?
A reference to the object is stored on the memory stack. Think of a reference as a pointer to that object’s data. This means that a simple assignment operation for primitive data types is actually a powerful reference mechanism for objects.
Note: Java provides the transient keyword for fields to indicate they don’t need to be stored with an object because their values don’t affect that object’s state. The result of the transient keyword is apparent only when using serialization.
int i1 = 10; int i2 = i1; //now i2 is 10 i2++; //i2 is now 11, but i1 is still 10
Lesson 3 83
Look at the following modified code that uses the Robot objects:
Robot robo1 = new Robot(); Robot robo2 = robo1;
robo1.name = “Marvin”; robo1.speed = 4.2;
robo2.name = “Chip”; robo2.speed = 12.8;
System.out.println(robo1.name + “ “ + robo1.speed); System.out.println(robo2.name + “ “ + robo2.speed);
The output would be the following:
Chip 12.8 Chip 12.8
This output may seem surprising until you realize that the variables robo1 and robo2 reference the same object. The assignment operation between objects doesn’t merely copy field values, but copies the pointer to the object from one to another.
The same principle applies to passing arguments to parameters. When passing an object as an argument, any modifications to the object will persist after the method returns. Unless this is the desired effect, you may prefer to copy the object’s values and specify a copy of the original object as an argument instead.
Class Members
By default, all fields and methods declared in a class will affect only a single object. These constructs are known as instance members. To access instance members, you must instantiate that class first and then access those members through the object reference using dot notation. The previous code examples demonstrate this type of access.
If you declare a field or method with the static keyword, then that field or method is now a class member. Setting class fields or invoking class methods will affect every object of the class. To access class members, you need only reference the
Programming in Java84
class itself in dot notation. As you may recall from the first lesson, the reason the main() method uses the static key- word is so that the Java runtime isn’t required to instantiate the class first. Only the class is loaded, not any of its objects.
Continuing our Robot class example, the following class members could be added:
static int totalRobots; static void stopAllRobots() {} To access these class members, you can use the class or an object of the class. For clarity, the preferred convention is to access class members using the class and not its objects. The following code accesses class members of Robot using both techniques:
Robot.stopAllRobots(); //preferred new Robot().stopAllRobots();
Access Modifiers
Access modifiers are keywords that determine the visibility of members to other classes. The two most common access modifiers are public and private. A member declared with the public keyword is available to all other classes, while a member declared with the private keyword is available only in that class.
Access modifiers are important tools for good encapsulation. Most fields should be declared as private, while associated accessor and mutator methods should be declared as public. By limiting availability to fields, you’re ensuring that other classes must use methods, rather than direct access. This limitation ensures that an object’s state is consistent and hidden from unnecessary modifications by other classes. The only exception to using private on fields is constants or other values that are required by other classes and don’t affect an object’s internal state.
Lesson 3 85
You would modify members of the Robot class to use good encapsulation as follows:
private String name; private int x,y; private int direction; private double speed; private static int totalRobots;
//accessors public String getName() {
return name; } public Point getCoordinates() {
return new Point(x,y); } public double getSpeed() {
return speed; } public int getTotalRobots() {
return totalRobots; } //mutators public void setName(String name) { this.name = name; } public void setSpeed(double speed) { this.speed = speed; } //functional methods public void turn (int direction) {} public void move(double time) {} public void move(double time, int direction) {} public static void stopAllRobots() {} The keyword this is used to reference the current running instance. When using a mutator, it’s common to name the parameter the same name as the field. To differentiate between the two variables, use the this keyword to reference the field and not the parameter. Pages 132–134 in Chapter 4 of the textbook detail this usage.
Note: The keyword this is used to reference the current running instance.
Programming in Java86
The previous example code that instantiates Robot objects will now need to be rewritten as follows:
Robot robo1 = new Robot(); Robot robo2 = new Robot(); robo1.setName(“Marvin”); robo1.setSpeed(4.2); robo2.setName(“Chip”); robo2.setSpeed(12.8); Notice the impact of accessor and mutator methods on how fields are used outside the class. If you provide a public accessor method for a private field, then the field becomes effectively read-only outside of the class. If both public muta- tor and accessor methods are provided, then the field is effectively read/write outside of the class. If no accessor or mutator method is provided, then the field is completely internal and unavailable outside the class.
Any calculation methods that are used only internally should also be declared private. Only those functional methods that must be exposed to other classes should be declared public. Java also provides two other access levels to provide granu- larity between private and public. The protected keyword is the same as using private, but with the addition of visibility to subclasses. If no access modifier is specified, then the default access is package level. With package level, the mem- ber is visible only to those classes within the same package. Inheritance and packages will be discussed in the next assignment.
Classes can also control their own visibility, but the language restricts access to only two levels: package level and public. By default, NetBeans declares all classes with the public keyword. Only nested classes can also use the private and protected keywords.
Note: You can define more than one class or other data type within a single source file. But only one of those types can be declared with the public keyword, and the filename must match the name of that public data type. Using an IDE like NetBeans that organizes applications into projects makes it easier to use different source code files for each data type. It’s a common practice to define more than one data type in a source file if only a text editor like Notepad or TextPad is used.
Lesson 3 87
Construction and Finalization
Within its lifetime, an object undergoes the following phases:
■ Referenced
■ Instantiated
■ Initialized
■ Used
■ Dereferenced
■ Finalized
■ Deleted
In the referenced phase, a variable is either declared or understood by the runtime to store a class pointer to the object. The class must be loaded to determine the reference type. The instantiated phase begins when the new keyword is used. In this phase, the space in the memory heap is reserved for the object.
The next phase is initialized. When an object is initialized, its default values are set on its fields. During the initialized phase, a specialized method called a constructor is invoked. A constructor method uses the same name as the class and implicitly returns an object of that class. If you’re confused why you haven’t seen a constructor yet, it’s because the com- piler automatically provides a default constructor to a class if no constructors are found. The default constructor has no parameters and an empty body.
For example, the Robot class has the following default constructor:
Robot() { }
You can do so much more with a constructor. Constructors can accept user-defined default values for an object’s fields and perform initial calculations or actions during object cre- ation. Like methods, constructors can also be overloaded. To reference another overloaded constructor, use the this key- word as you would when referencing instance fields.
Note: The access modi- fier for the default constructor matches the access modifier of the class. If the Robot class was declared public, then the default constructor would include the public keyword.
Programming in Java88
The following code demonstrates overloaded constructors for the Robots class:
Note: Most constructors are public or package level. Some constructors are private to prevent instantiation by other classes. The Math class is a good example of this. Although the Math class provides useful constants and methods, this functionality isn’t dependent on instance fields or methods. Because instantiation isn’t required to use the class, the class prevents instantiation.
Although this may seem like a lot of work when writing a class, it greatly simplifies object creation down the road. Instead of manually initializing fields or using mutator methods, you can now create an object with all of the values you need with a single line of code:
Robot robo1 = new Robot(“Marvin”, 4.2); Robot robo2 = new Robot(“Chip”, 12.8);
You might be wondering if there’s a way to perform initialization on class fields when a class is loaded, similar to how instance fields are initialized using constructors. Pages 209–213 of Chapter 6 in the textbook describe how to use the static block for this purpose.
public Robot() {//invokes 2nd constructor this(“Unnamed”); } public Robot(String name) {//invokes 3rd constructor this(name,0); } public Robot (String name, double speed) {//invokes 4th constructor this(name,speed,0,0); } public Robot (String name, double speed, int x, int y) {//workhorse this.name = name; this.x = x; this.y = y; this.speed = speed; totalRobots++; }
Lesson 3 89
An object is in the used phase until the last variable that ref- erences it goes out of scope. When that happens, the object is now dereferenced. Dereferenced means that there are no live pointers to the object, and the space it occupies in memory could be used for other data.
In some runtime environments, you would then need to per- form the operations to delete the object from memory and reclaim it for usage with other objects. Provided by the JVM, an automated service known as the garbage collector performs this deletion and reclamation for you. The garbage collector “takes out the garbage” only when there’s a significant amount of memory being consumed by dereferenced objects. This is especially the case when available system memory is below what’s required for Java applications.
Because you can’t plan for when the garbage collector performs its work, you can use the finalize() method for any opera- tions that must be done before the object is removed. When the finalize() method is executed by the garbage collector, the object is now in the finalized phase immediately before dele- tion. Once an object is in the deleted phase, its memory can be reclaimed for other objects.
Activity 9: Create a Class and Use Constructors
1. Create a new Java Application project named Lesson3Activity9 in NetBeans.
2. Create a new public class named Polygon in the project.
a. You can either right-click on the Lesson3Activity9 project or choose New > JavaClass … in the context menu by right-clicking the Lesson3activity9 pack- age in Projects or use the CTRL+N keyboard shortcut and choose Java Class in the File Types pane and click the Next button (Figure 7).
b. In the Class Name text box, type Polygon and in the Package drop-down list, choose lesson3activity9.
c. Click the Finish button.
Programming in Java90
3. First, create a non-encapsulated class. Inside the Polygon class add the following code:
4. Open the Lesson3Activity9.java file. You can do this either by clicking its tab at the top of Documents because it should be open or by double-clicking the Lesson3Activity9.java file in the Projects pane.
String id; int numSides, lenSides; void printInfo() { System.out.print(id + “: “); System.out.println(numSides + “ sides with length of “ + lenSides); }
FIGURE 7—Create a New Class
Lesson 3 91
5. In the main() method of the Lesson3Activity9 class, add the following code and consider what the output should be for this code.
Polygon triangle = new Polygon(); Polygon square = new Polygon(); Polygon octagon = new Polygon(); triangle.id = “triangle1”; triangle.numSides = 3; triangle.lenSides = 5; square.id = “square1”; square.numSides = 4; square.lenSides = 3; octagon.id = “octagon1”; octagon.numSides = 8; octagon.lenSides = 10; triangle.printInfo(); square.printInfo(); octagon.printInfo();
6. Build and run the project. Did the output match your expectations?
Notice how the code in the main() method is lengthy and requires significant understanding of the Polygon class. Also, the Polygon class doesn’t provide much functionality or cal- culations that could be helpful when using polygons. In the next section, you’ll modify the Polygon class to use proper encapsulation and store a polygon’s perimeter and area.
7. Open the Polygon.java file. You can open the file either by clicking its tab at the top of Documents because it should be open or by double-clicking the Polygon.java file in the Projects pane.
8. Modify the code in the Polygon class as follows:
private String id; private int numSides, lenSides;
//calculated fields private int perimeter; private double area;
//internal calculations
Programming in Java92
private void calculatePerimeter() {
perimeter = numSides * lenSides;
}
private void calculateArea() {//Uses the Math class
double numerator, denominator;
numerator = Math.pow(lenSides, 2) * numSides;
denominator = 4 * Math.tan(Math.toRadians(180/numSides));
this.area = numerator / denominator;
}
//accessor/mutators
public String getID() { return id; }
public void setID (String id) { this.id = id; }
public int getSides() { return numSides; }
public int getSideLengths() { return lenSides; }
public int getPerimeter() { return perimeter; }
public double getArea() { return area; }
public Polygon(String id, int numSides) {
this(id, numSides, 1);
}
public Polygon(String id, int numSides, int lenSides ) {
this.id = id;
if (numSides < 3)
throw new IllegalArgumentException(“Polygon must have at least 3 sides!”);
this.numSides = numSides;
if (lenSides < 1)
throw new IllegalArgumentException(“Polygon must have sides greater than 0!”);
this.lenSides = lenSides;
//perform calculations
calculatePerimeter(); calculateArea();
}
public void printInfo() {
System.out.print(id + “: “);
System.out.println(numSides + “ sides with length of “ + lenSides);
System.out.println(perimeter + “ perimeter with area of “ + area);
}
Lesson 3 93
Now your code in the main() method would be significantly simplified and more information is available from the Polygon class. In the next section, you’ll replace the main() method code to use the improved Polygon class.
9. Open the Lesson3Activity9.java file. You can do this either by clicking its tab at the top of Documents because it should be open or by double-clicking the Lesson3Activity9.java file in the Projects pane.
10. Notice all of the red squiggly lines in the main() method! Because Polygon no longer has a default constructor and its fields are now hidden from other classes, there are a significant number of compilation errors!
11. Modify the code in the main() method as follows:
Polygon triangle = new Polygon(“triangle1”, 3, 5); Polygon square = new Polygon(“square1”, 4, 3); Polygon octagon = new Polygon(“octagon1”, 8, 10);
//all other main() code is deleted
triangle.printInfo(); square.printInfo(); octagon.printInfo();
12. Build and run the project. The output should now include the perimeter and area of each polygon. Feel free to build some more Polygon objects in the main() method, so that you can become more familiar with instantiating and using well-encapsulated classes.
Nested Classes
Although sparingly used, Java allows you to define a class within another class. The inner class is known as a nested class. This capability is intended for the rare circumstance where a class is completely dependent on another class and increased encapsulation could reduce complexity. When using AWT and Swing, you’ll see some examples of nested classes, even anonymous ones!
Programming in Java94
Sometimes a nested class indicates that an object contains another object. In other scenarios, a nested class is simply a class placed within another because it needs access to unavailable fields or methods. The first situation describes non-static nested classes, while the second describes a static nested class. As you might expect, a static nested class is declared using the static keyword.
Here is an example of a non-static nested class:
public class Polygon { Side[] sides; public class Side {
int length, angle; }
}
Note: Although nested classes are often intended to provide further encapsulation, the code above is a poor example of good encapsulation. The example is intended to simplify the syntax. If this were encapsulated better, then the fields would be private, and public accessors and mutators would be defined in both the outer and inner classes.
In this example code, the class Polygon has an inner class named Side. Notice that the Polygon class references the Side class using an array. The nested class then represents the relationship that a polygon contains many sides.
How do you access an inner non-static class? Because the inner class is dependent on objects of the outer class, you must first instantiate the outer class and then instantiate the inner class. As you might imagine, this situation creates some unusual-looking code when using dot notation.
This code creates a Side object:
Polygon.Side side1 = new Polygon().new Side();
The declaration of the side1 variable makes sense, because a Side object is nested within the Polygon class. But the portion on the right side of the assignment seems very bizarre. It’s for good reason. Java initially didn’t support inner classes, so the existing instantiation syntax was reused to accommodate the new feature.
Lesson 3 95
If the Side class was declared as a static nested class of Polygon by adding the static keyword, the syntax is more logical and easier to read:
Polygon.Side side1 = new Polygon.Side();
If you’re unsure when you’ll define nested classes, the answer is probably rarely if ever. But you’ll find yourself using nested classes when handling GUI elements and events.
Programming in Java96
Self-Check 8
1. What is the difference between object references and primitive types?
__________________________________________________________
2. What is object encapsulation?
__________________________________________________________
3. What is the difference between instance and class members?
__________________________________________________________
4. When is a class instantiated? When is an object finalized?
__________________________________________________________
Check your answers with those on page 204.
Lesson 3 97
ASSIGNMENT 9: CREATE CLASS INHERITANCE AND PACKAGES Read Assignment 9 in this study guide. Then read Chapter 7, Chapter 8, pages 268–278, and Chapter 12, pages 427–429, in your textbook.
Assignment 9 addresses how to inherit code from classes, class hierarchies, and Java packages. Be sure to complete the Try This activities in Chapters 7 and 8; they’ll help rein- force the syntax and concepts.
Classes and Subclasses
As described in the previous assignment, classes can be thought of as ways of classifying like objects. As with most classification schemes, objects can become more and more specialized based upon the class in which they belong. Extending the previous example of a Robot class, you could have specific types of robots based on algorithm such as a BinarySearchRobot, on function such as a CarDriverRobot, or on built-in capabilities such as a CameraRobot. Although all of these classes are different and represent unique sets of objects, they also share state and behavior mechanisms. For example, all of these robots can move at a certain speed and can be tracked using x and y coordinates.
Inheritance describes how subclasses can reuse code from the same class. The subclass is the one that’s specialized, while the superclass is the generalization. To take advantage of inheritance in Java, you use the extends keyword when declaring the subclass. Only single inheritance is supported in Java, so that a subclass can have only one direct superclass.
The following code declares a subclass of the Robot class:
public class CameraRobot extends Robot { private boolean pathBlocked; private int cameraDirection; public boolean isPathBlocked() { return pathBlocked; } public int getCameraDirection() {
Programming in Java98
return cameraDirection; } public void turnCamera(int cameraDirection) { this.cameraDirection = cameraDirection; } }
You may not see it, but code inside the Robot class is now automatically part of the CameraRobot class because of the extends keyword. The CameraRobot class only needs to con- tain code that specializes it as a subclass.
There’s also a wider implication when considering object references. Any CameraRobot objects are now typed not only by the CameraRobot class, but also by the Robot class. The compiler will allow you to declare variables of type Robot and they can reference both Robot and CameraRobot objects!
The following code demonstrates the specialization principle of subclasses:
CameraRobot cbot1 = new CameraRobot(); Robot cbot2 = new CameraRobot();
The difference between these two object references will be discussed in the Polymorphism section.
What Is Inherited?
When defining a subclass, it’s important to realize that not everything is inherited. All fields and methods, both class and instance members are inherited. Constructors, however, aren’t inherited from the superclass. When a subclass construc- tor is invoked, an associated superclass is invoked implicitly. Since a subclass is a specialized type of its superclass, instantiation of a subclass must, by definition, instantiate the superclass as well. Therefore, you’ll need to copy the same constructors over to the subclass if you wish to offer the same initialization functionality provided by the superclass. Although superclass instantiation occurs automatically, you should use the super keyword to invoke superclass construc- tors and increase code reuse. To access fields, and methods located in the superclass, you can also use the super keyword in place of the this keyword.
Note: An explicit invo- cation to superclass constructor must be the first line within a subclass constructor because the superclass must be instantiated before the subclass.
Lesson 3 99
The following code contains the constructors for the CameraRobot subclass:
Of the items that are inherited, not every one is available to the subclass. Availability depends on access modifiers. If access is the default package level, then only subclasses in the same package will have access to those members. If the keyword protected was used, then subclasses in whichever packages they’re located will have access to those members. Even in subclasses, members declared with the private key- word aren’t accessible.
It may seem odd to inherit members that are inaccessible, but this is actually very common among real-world objects. Although you may inherit traits from your mother or father, many of those traits aren’t available for modification. For better or worse, you’re stuck with them!
Overriding Methods
Subclasses can do more than overload superclass methods; they can override them. As you recall from the previous lesson, the method signature is how the runtime figures out which method should be invoked. In overloading, more than one method has the same name, but specifies a different order
public CameraRobot() { this(“Unnamed”);
} public CameraRobot(String name) {
this(name,0); } public CameraRobot (String name, double speed) {
this(name,speed,0,0); } public CameraRobot (String name, double speed, int x, int y) {
this(name, speed, x, y, 0); } public CameraRobot (String name, double speed, int x, int y, int cameraDirection) {
super(name,speed,x,y); pathBlocked = false; this.cameraDirection = cameraDirection;
}
Programming in Java100
of data types for parameters. In overriding, a subclass can use the same name and order of parameter data types as a method in the superclass. This means that the subclass ver- sion of the method effectively replaces the method version in the superclass.
The following method in the CameraRobot class overrides the move() method in the Robot class:
@Override public void move(double time) { //check if the path is blocked }
Note: The previous code uses the @Override annotation, which is used by the compiler to check that the method signature matches a method in the superclass. Not all annotations are useful during development, but the @Override annotation is essential to making sure you override instead of overload a superclass method. Annotations are introduced on pages 430–432 in Chapter 12 of the textbook.
How does the runtime know which version of the move() method is intended? Not surprisingly, the runtime chooses the version based on which class the object instantiated. If you invoke move() on a Robot object, then its version is executed. If you invoke the move() on a CameraRobot object, then the move() method defined in that class is executed.
As you recall from the previous lesson, the final keyword is used in Java to declare constants. The final keyword can also be used in inheritance. A method declared with the final keyword can’t be overridden by subclasses. If a class is declared with the final keyword, then it can’t have subclasses at all. Some built-in classes provided by Java are declared as final, because all or most of their methods are so complex, that inheritance isn’t recommended.
Although not recommended at all, you can use subclass hiding to replace fields and methods inherited from a superclass. Hiding is the process of using syntactic loopholes to prevent the side effects of normal inheritance. To hide a field, simply declare a field in the subclass as it’s named in the superclass. Because static methods can be accessible from instances as you learned in the previous assignment, you can also hide a
Lesson 3 101
superclass method by using the same method signature with the static keyword in the subclass. Polymorphism, as described in the next section, doesn’t apply to hidden class methods, only overridden instance methods.
It makes sense in the Robot example scenario to use method overriding. A regular Robot object has no sensors to detect its surroundings, while a CameraRobot object can actually see and verify whether its path is blocked. But if you find your- self overriding a majority of methods, you may want to reconsider whether inheritance is a good idea. If most of the inherited code is being replaced, then why inherit it in the first place? A better choice might be an interface, as you’ll learn in the next assignment.
Object References and Polymorphism
Now, revisit the following example code:
CameraRobot cbot1 = new CameraRobot(); Robot cbot2 = new CameraRobot();
Although both lines of code instantiate a CameraRobot object, the first line uses a CameraRobot object reference and the second line uses a Robot object reference. Using the cbot1 variable will provide access to the members in the CameraRobot and Robot classes. This makes sense because the CameraRobot class is a subclass of Robot and it inherits its members.
The cbot2 variable is more limited, however. Because this variable is a Robot object reference, only those members in the Robot class are accessible. The cbot2 variable does point to a CameraRobot object, so you could use casting to get access to CameraRobot members. The following code demonstrates the technique:
CameraRobot cbo2AsCameraRobot = (CameraRobot) cbot2;
Now, take the following example code:
Robot bot1 = new Robot(); Robot bot2 = new CameraRobot();
Programming in Java102
Unlike the previous example, bot1 and bot2 use the same object reference type, but point to different types of objects. The variable bot1 references an object of the superclass Robot, while variable bot2 references an object of the sub- class CameraRobot. Because both variables are using the Robot class as the object reference, only those members in the Robot class are accessible.
With what you’ve learned so far about object references, what do you think will happen when the following code is run?
bot1.move(2.8); bot2.move(5.4);
Surprisingly, when dealing with overridden methods, the ref- erence type of the variable has no effect on which version of the move() method is executed. The move() method defined in the Robot class is executed for bot1, while the version in the CameraRobot class is executed for bot2. This result is known as polymorphism. In polymorphism, the actual method that’s executed depends on the type of the object, not the reference type of its variable.
The Object Class
In Java, even if you don’t use inheritance, every class is a subclass of the Object class. What this means is that every class has built-in functionality inherited from the Object class. Thus, you can invoke the getClass() on any object and it will return a reference to its class. The table on page 265 of Chapter 7 in the textbook lists all methods inherited from the Object class.
There are three methods that you’ll commonly override in your classes: toString(), equals(), and hashCode(). The toString() method is intended to provide a text representation of an object for quick output. You’ve used the equals() method before with String objects. The equals() method returns a boolean value indicating whether the current object and an object argument are equivalent. If you choose to override the equals() method, you must also override the hashCode() method. The hashCode() method returns an int value that should be the same if two objects are equivalent.
Note: You can use the instanceof operator to verify whether an object is an instance of a specified class. This is preferred before performing a reference type cast.
Lesson 3 103
The following code overrides the toString() method for the Robot class:
Remember: Because it’s a subclass of Robot, the CameraRobot class also inherits the overridden toString() method.
Abstract Classes
There will be some situations where a class is intended only for generalizing a group of classes and instantiation doesn’t make sense. Although there are many methods in the superclass that won’t be overridden, some methods may be overridden by every subclass. In other words, these method signatures may be the same across classes, but the actual code defined in each method will be different.
One solution to this problem is an abstract class. An abstract class is one that can’t be instantiated and can include methods without definition code. The class is declared with the abstract keyword and each method that isn’t defined must also include the abstract keyword. Although an abstract class can’t be instantiated, it can include constructors that subclasses can invoke.
The following code defines an abstract class named MovableMachine:
public abstract class MovableMachine { private int x,y; private int direction; private double speed; public Point getCoordinates() {
return new Point(x,y); } public double getSpeed() {
return speed; } public void setSpeed(double speed) {
this.speed = speed; }
@Override public String toString() {
return name + “at “ + x + “, “ + y + “ with speed of “ + speed; }
Programming in Java104
//abstract methods public abstract void turn (int direction);
public abstract void move(double time); }
Because an abstract class can’t be instantiated, subclasses are required for actual usability. Subclasses of an abstract superclass are known as concrete classes, because they must provide the definition of all abstract methods. This require- ment to provide definition for abstract methods is known as a contract. If a subclass doesn’t provide definition for abstract methods, then that subclass also must be declared abstract and rely on its own subclasses to provide those definitions.
Activity 10: Create an Abstract Class and Subclasses
1. Launch NetBeans and open the Lesson3Activity9 proj- ect if you’ve closed out of the NetBeans.
2. Create a new public class named Shape in the project. Review step 2 of Activity 9 if you need help performing this action.
3. The Shape class should be defined as follows:
public abstract class Shape { private String id; //calculated fields protected int perimeter; protected double area; public Shape(String id) { this.id = id; } //accessor/mutators public String getID() { return id; } public void setID (String id) { this.id = id; } public int getPerimeter() { return perimeter; } public double getArea() { return area; } //internal abstract calculations protected abstract void calculatePerimeter(); protected abstract void calculateArea(); public void printInfo() {System.out.print(id + “: “);} }
Lesson 3 105
Notice the area and perimeter fields and calculatePerimeter() and calculateArea() methods are now declared with the protected keyword. Why is that required?
4. Open the Polygon.java file either by clicking its tab at the top of Documents because it should be open or by double-clicking the Polygon.java file in the Projects pane.
5. Modify the Polygon class declaration to inherit from the Shape class as follows:
public class Polygon extends Shape
6. Because the Polygon class now inherits code from the Shape class, you need to remove the id, perimeter, and area fields and getID(), setID(), getPerimeter(), and getArea() methods.
7. Because the calculatePerimeter() and calculateArea() methods are declared with the protected keyword in the Shape class, you need to change the private keyword to protected on these methods in the Polygon class.
8. Replace the statement this.id = id; in the second Polygon constructor with the statement super(id);
9. Replace the statement System.out.print(id + “: “); in the printInfo() method with the statement super.printInfo();
10. Open the Lesson3Activity10.java file and modify the first four lines in the main() method as follows:
Shape triangle = new Polygon(“triangle1”, 3, 5); Shape square = new Polygon(“square1”, 4, 3); Shape octagon = new Polygon(“octagon1”, 8, 10); Shape hexagon = new Polygon(“hexagon1”, 6, 5 );
11. Build and run the project. The output should match the output at the end of Activity 9.
The reason this code works is because of polymorphism. In the next section, you’ll add another subclass of Shape named Circle.
12. Create a new public class named Circle in the project.
Note: You could copy and paste the code from the Polygon.java file and modify it, rather than retyping it all. Remember the key- board shortcuts are CTRL+C for copy and CTRL+V for paste.
Programming in Java106
13. The Circle class should be defined as follows:
14. Open the Lesson3Activity9.java file and add the follow- ing code to the main() method:
Shape circle = new Circle(“circle1”, 5);
circle.printInfo();
15. Build and run the project. You should now have both Polygon and Circle objects using the Shape class and through polymorphism displaying the correct results!
public class Circle extends Shape { private int radius; protected double perimeter; //hides Shape field public Circle(String id, int radius) {
super(id); this.radius = radius; calculatePerimeter(); calculateArea();
} //accessors/mutators public int getRadius() { return radius; } public int getDiameter() { return 2 * radius; } //calculations protected void calculatePerimeter() {
perimeter = 2 * Math.PI * radius; } protected void calculateArea() {
area = Math.PI * Math.pow(radius, 2); } public void printInfo() {
super.printInfo(); System.out.println(“radius of “+ radius); System.out.println(perimeter + “ perimeter with area of “ + area);
} }
Lesson 3 107
Define a Package
To avoid naming conflicts between classes and other types, Java uses a unit of organization known as a package. A package groups related types into a logical namespace. Each package can in turn have sub-packages, so that the result is an organized hierarchy of data types.
Rather than requiring a complex name for a class such as PokerGamePlayingCardDeck, you could create a package with the name games.poker.cards and simply rename the class Deck. In the package games.poker.cards, you would expect to find other card-related classes used in a poker game, such as Card, PlayerHand, DealerHand, and River. Because the dot-notation includes other packages (games, games.poker), you would expect to find a more general Player class in the games package and perhaps a Bet class in the games.poker class.
To define a package, you must perform two actions:
1. Use the package statement in all related source code files.
2. Place the source code files in the same folder structure required for the package.
All source code files in the same package should include a package statement with that name. The following is an example package statement for the Robot and CameraRobot classes:
package games2d.maze;
The package statement must be the first line of executable code. This means that comments and annotations can pre- cede the package statement, but no other elements. Common convention is to use all lowercase letters for package names, but all other characters allowed in Java identifiers can also be used.
If no package statement is included in a source code file, then the data type(s) in the source code file are placed in the default package. The default package is global level, meaning that no package name is required to access the data type(s). If a package statement is included, then the package name is automatically prepended to the data type name(s). With the
Programming in Java108
package statement above, the full names of the Robot and CameraRobot classes are now games2d.maze.Robot and games2d.maze.CameraRobot.
Finally, you must place the source code files in the package in the same folder structure as indicated in the package state- ment. That means for the Deck class in the games.poker.cards package, you need to move the Deck.java file into the \games\poker\cards folder. For the files Robot.java and CameraRobot.java, you need to move them into the \games2d\maze folder. After compiling the files, the compiled files (.class) should also remain in this folder structure or be compressed into a self-contained JAR file. Remember: Java package names are case-sensitive, so you should make sure the folder names are all lowercase as well.
The location of these package folders must be specified in the CLASSPATH environmental variable if running the files man- ually on the command-line using the java executable. This development environment can be tedious and error-prone.
Luckily, the NetBeans IDE automates the creation, compila- tion, and running of packages. Each project you’ve developed in NetBeans is part of a package with the same name as your project, but in all lowercase. To create a new package, either choose New > Java Package … in the context menu when right-clicking on the Source Packages folder in Projects or use the CTRL+N keyboard shortcut and choose Java Package in the File Types pane and click the Next button. You can create a dot-notated sub-package such as pack.subpack or manually create a package named pack and then right-click on the pack package and create a new package named subpack.
Lesson 3 109
Using a Package
As described in the last section, data types inside packages now have longer names and these longer names are required to access those data types. Now that Robot and CameraRobot are in the games2d.maze package, their full name is required when accessing them outside that package. The following example demonstrates this.
games2d.maze.Robot bot1 = new games2d.maze.CameraRobot();
Although the compiler or runtime has no problem with longer names for data types, some programmers do. To resolve this issue, you can use the import statement. The import state- ment allows you to use shortened names for the data type(s) in the package you import. You can import either one data type at a time (preferred by NetBeans) or all data types in a package using * as a wild card.
The following import statements will allow you to use the Robot and CameraRobot with their shortened names:
These import statements will be stripped out after compilation, so they’re only intended to reduce the number of keystrokes when using data types from other packages. So don’t worry about having too many import statements affecting runtime performance. The import statement must come after the package statement if it exists and before any other executable code.
Note: Declaring explicit import statements is good programming practice, but NetBeans provides a lazy import as needed. If a data type isn’t recognized in your code, NetBeans will place a red squiggly line below the data type with the message can’t find symbol. Simply right-click on the source code file and choose the Fix Imports option from the contextual menu. A dialog box will then appear allowing you to choose which packages you need to import if there’s a conflict. After click- ing the OK button in the Fix All Imports dialog, NetBeans will automatically add the required import statements for you (Figure 8).
Note: As you recall from the graded projects, you used the Scanner class to handle user input. Because the Scanner class was located in the java.util package, you had to use the full name java.util.Scanner in that code.
Note: Only types within a package are imported, not sub-packages.
import games2d.maze.*; //imports both Robot and CameraRobot import games2d.maze.Robot; import games2d.maze.CameraRobot;
Programming in Java110
One word of caution when using import statements: conflicts. If you import too many packages, then possibly conflicting data types will require long names anyway. For example, there’s a Robot class in both the games2d.maze and java.awt packages. In the scenario where there’s a conflict between classes, you’ll need to choose which package to import and which class(es) you’ll need to use the longer name.
Finally, you can also use a special type of import statement known as static import. For classes that contain class mem- ber exclusively, that static import statement can be used to omit the class when using its members. The best example of doing this is the Math class. The Math class contains no instance members, only class constants and methods. Rather than typing Math.PI to use this constant, you can use a static import statement to abbreviate the reference to PI.
The following code example uses a static import statement for the Square class:
import static java.lang.Math.pow;
public class Square { private int sideLength; private double calculateArea() {
return pow(sideLength, 2); }
}
In this example, the code can reference the class method pow() without the package or class name. You can also use the * as a wildcard character to import all class members. Oracle recommends using static import statements spar- ingly, because they can create some very confusing and disorganized code if used all the time.
In the following activity, you’ll create a new package for the Shape, Circle, and Polygon classes and then import that package.
Figure 8—Fix All Imports Dialog
Lesson 3 111
Activity 11: Create and Import a Package in NetBeans
1. Launch NetBeans and open the Lesson3Activity10 project if you’ve closed out of the NetBeans.
2. Create a new java package named geometry.shapes2d. To create a new package, either choose New > Java Package … in the context menu when right-clicking on the Source Packages folder in Projects or use the CTRL+N keyboard shortcut and choose Java Package in the File Types pane and click the Next button. Then, type geometry.shapes2d in the Package Name textbox and click the Finish button.
3. Move the Circle.java, Polygon.java, and Shape.java files into the geometry.shapes.2d package. To do this, you should click and drag each file from the lesson3activity10 package on top of the geometry.shapes2d package in the Projects pane.
Note: For each package move, you’ll be prompted by the Move Class dialog for verification. By default, NetBeans will refactor, meaning that each moved file will have the package statement automatically added to the top and any file that referred to the old package will now have an import statement referring to the new one. Click the Refactor button on this dialog to continue.
4. Open the Circle.java, Polygon.java, and Shape.java files one at a time. Notice the new package statement at the top added by NetBeans.
5. Open the Lesson3Activity10.java file. Notice the new import statement at the top added by NetBeans.
6. Build and run the project. The output should be the same as that at the end of the previous activity.
Programming in Java112
Common Packages
The Java SE 7 platform comes with existing packages you can use. The documentation of these data types is known as the application programming interface (API) specification. The API specification describes an overview of each data type, its superclasses and subclasses, and fields and methods. You can either download this documentation or access the API specification remotely on Oracle’s website at http://docs.oracle.com/javase/7/docs/api/.
Note: In NetBeans, you can view the API documentation for a built-in class or one of its methods very easily. Either right- click on the class or its member and choose the Show JavaDoc option from the context menu or use the ALT+F1 keyboard shortcut. JavaDoc is the older name associated with Java API documentation.
Page 278 in Chapter 8 includes the top-level packages originally found in java. The java.lang package contains the fundamental types required by the Java language, so it’s always imported implicitly. Not surprisingly, the basic input and output types are found in the java.io and java.nio pack- ages, while networking-related features are in java.net. The java.applet package is used to create applets, while graphics and painting uses the java.awt and javax.swing packages.
One important package omitted from the textbook is the java.util package. This package contains the collections framework and other utility classes like the Scanner class. The collections framework contains powerful list structures that offer more flexibility and generally better performance than arrays. Unlike arrays, collections aren’t fixed in size and provide built-in sorting and searching capabilities.
Table 3 contains common collection classes you might find useful. Because most collections use generics to handle dif- ferent types, usage of a collection will be delayed until that section in the lesson.
Lesson 3 113
Class Description
ArrayList A resizable list of index-ordered elements with next/back iteration
HashMap A resizable set of unordered elements retrievable by key
LinkedList A resizable list of index-ordered elements with next/backiteration and stack/queue functionality.
TreeMap A resizable set of elements ordered in hierarchical sortingalgorithm and retrievable by key.
Table 3—Common Collection Classes
Programming in Java114
Self-Check 9
1. What is inheritance? Which class is the superclass and which is the subclass?
__________________________________________________________
2. Given the following code, what is the output?
public class SuperClass {
public void print() {System.out.println(“Super print()”);
}
class SubClass extends SuperClass {
public void print() {System.out.println(“Sub print()”);}
public static void main(String[] args) {
SuperClass obj = new SubClass();
obj.print();
}
}
__________________________________________________________
3. What is the difference between abstract and concrete classes?
__________________________________________________________
4. Which two purposes does a package serve in Java?
__________________________________________________________
Check your answers with those on page 204.
Lesson 3 115
ASSIGNMENT 10: CREATE INTERFACES AND ENUMERATIONS Read Assignment 10 in this study guide. Then read Chapter 8, pages 278–292, and Chapter 12, pages 406–420, in your textbook.
Assignment 10 adds two other reference types used in Java: interfaces and enumerations. This study guide will introduce you to the selected sections in Chapter 8 and Chapter 12. Be sure to complete the Try This activities in both chapters. They’ll help reinforce the syntax and concepts.
Interface and Implementation
When considering a class, it’s important to differentiate between a class’s interface and its implementation. An inter- face is the declaration of each method, including the method name, parameter list, and return value. The implementation is code that defines how the method uses the arguments as input and returns the result as output. The implementation is the code between the opening and closing curly braces.
For the following method in the Square class, the interface is bolded and the implementation is italicized:
public double getArea() {
return Math.pow(sideLength, 2);
}
The interface describes what an object can do, while the implementation defines how the object does it.
Inheritance without the Side Effects
Although inheritance provides reuse and encapsulation among subclasses, it also creates tight-coupling between these classes. This means that any implementation changes in the superclass will affect all subclasses and their implementation. Although the subclasses share the same interface, their implementation may be unrelated and doesn’t require inheritance.
Programming in Java116
In many situations, inheritance doesn’t make sense. Classes may share the same interface, but inherit code from different superclasses. Take the following class as an example:
public class Mouse { public void eat () {} public void sleep() {} public void turn (int direction) {} public void move(double time) {} public void move(double time, int direction) {}
}
The Robot and Mouse classes both share some methods, namely move() and turn(), but in all other ways they’re dis- similar. A Robot object can’t eat or sleep, while a Mouse object can’t be tracked using x and y coordinates. It wouldn’t make sense to create some superclass named Movable just for a single method!
Not only that, but because Java supports only single inheritance, the Robot and Mouse classes couldn’t share one superclass and be subclasses of another. It would make logical sense for Robot to have a superclass like Machine and Mouse to have a superclass like Animal. Neither the Robot nor Animal class can be subclasses, unless they give up inheritance with their other superclasses.
To overcome these design issues, Java provides the interface keyword to separate out just the interface portion from a class. Unlike abstract classes, interfaces can contain no private fields or method implementations, only constants, initialized fields, and method declarations. A class can have only one immediate superclass, but it can implement zero or more interfaces.
To resolve the issue with the Robot and Mouse classes, you could declare a new interface called Movable that contains only shared methods between the two classes. The following code demonstrates one way to define the Movable interface:
public interface Movable { public void turn (int direction); public void move(double time); public void move(double time, int direction);
}
Lesson 3 117
The Robot and Mouse classes would use the implements keyword in their class declarations as follows:
Similar to inheriting an abstract class, classes that imple- ment an interface must define all methods of that interface. Interfaces are also treated as powerful reference types and support polymorphism. Implementing an interface is known as “inheritance without the side effects.” This is because only the interface is inherited, not the implementation details that are bound to change from class to class. The interface is less likely to change, so that classes that communicate using interfaces are known as loosely-coupled.
How powerful is an interface? Take the following method as an example:
The moveInMaze() method will move a Mouse, Robot, or any other object that implements the Movable interface. The implementation of the moveInMaze() method doesn’t need to be concerned with implementation details, but only how to use the interface. Even though a Mouse object can eat and sleep, using an interface allows other classes to focus on what they need to do with the object, not be concerned with all of the class details that aren’t important with the task at hand.
Activity 12: Create and Use an Interface
1. Launch NetBeans and open the Lesson3Activity11 project if you’ve closed out of the NetBeans.
2. Add a new interface named Nameable.
public class Mouse extends Animal implements Movable {/*implementation omitted*/}
public abstract class Robot extends Machine implements Movable {/*implementation omitted*/}
Note: In abstract classes, methods with no definition must use the keyword abstract. The keyword abstract isn’t required in this code, because all meth- ods in an interface contain no definition.
public void moveInMaze( Movable m, double time, int direction) { m.move(time, direction);
}
Programming in Java118
You can either right-click on the Lesson3Activity11 project and choose New > Java Interface … in the con- text menu by right-clicking the lesson3activity11 package in Projects or use the CTRL+N keyboard short- cut and choose Java Interface in the File Types pane and click the Next button.
In the Class Name text box, type Polygon and in the Package drop-down list, choose lesson3activity11.
3. The Nameable interface will contain three methods for objects with names and descriptions. The code for the Nameable interface should be as follows:
public interface Nameable { public String getID(); public void setID (String id); public void printInfo(); }
4. Open the Shape.java file in the geometry.shapes2d package.
5. Modify the Shape class declaration to implement the Nameable class as follows:
public abstract class Shape implements Nameable
6. Right-click somewhere in the source code file and choose the Fix Imports option from the contextual menu. This will add the import statement for the interface automatically.
Now that you’ve created an interface for objects with names and descriptions, you’ll create another class unrelated to two-dimensional shapes. This new class represents a geometric proof that contains a name and description, but has no other similarity with the Polygon and Circle classes.
Note: The interface contains very little code. Because classes that implement an interface must provide implementation for all methods declared in an interface, most inter- faces are specialized and brief.
Lesson 3 119
7. Create another class named Proof to the geometry package.
■ You can either right-click on the Lesson3Activity project in Projects and choose New > Java Class … in the context menu or use the CTRL+N keyboard shortcut and choose Java Class in the File Types pane and click the Next button.
■ In the Class Name text box, type Proof and in the Package drop-down list, type geometry.
8. The Proof class should be defined as follows:
9. Right-click somewhere in the source code file and choose the Fix Imports option from the contextual menu. This will add the import statement for the interface automatically.
public class Proof implements Nameable { private String id; private String prove; private String[] given; public Proof(String id, String prove, String... given) {
this.id = id; this.prove = prove; this.given = given;
} //Nameable implementation
public String getID() { return id; } public void setID(String id) { this.id = id; } public void printInfo() {
System.out.print(id + “: “); System.out.print(“\nProve: “ + prove); System.out.print(“\nGiven: “ +
Arrays.toString(given)); } }
Programming in Java120
10. Open the Lesson3Activity11.java file and modify the following code in the main() method:
11. Right-click somewhere in the source code file and choose the Fix Imports option from the contextual menu. This will add the import statement for the Proof class automatically.
12. Build and run the project. You should now have all three objects, Polygon, Circle, and Proof objects using the Nameable interface and through polymorphism displaying the correct results.
Creating Basic Enumerations
Using names for values rather than literal values themselves makes code more readable. This is especially the case for numerical values. It’s easier to remember that a number is the width of a box if it’s named with the variable boxWidth, than it’s simply as its value of 8.5.
Nameable triangle = new Polygon(“triangle1”, 3, 5);
Nameable square = new Polygon(“square1”, 4, 3);
Nameable octagon = new Polygon(“octagon1”, 8, 10);
Nameable hexagon = new Polygon(“hexagon1”, 6, 5 );
triangle.printInfo();
square.printInfo();
octagon.printInfo();
hexagon.printInfo();
Nameable circle = new Circle(“circle1”, 5);
circle.printInfo();
Nameable proof = new Proof(“Congruent triangles”, “ABM and DCM are congruent”,
“AD bisects BC”, “BC bisects AD”);
proof.printInfo();
Lesson 3 121
Simply described, an enumeration is a custom data type that contains a limited set of named values. An enumeration is described in Java using the enum keyword. The following code defines an enumeration for e-mail messages:
public enum MailPriority { REQUIRED_RESPONSE, REQUIRED_ACKNOWLEDGEMENT, OPTIONAL_RESPONSE, OPTIONAL_ACKNOWLEDGEMENT }
Like constants, enumeration values are by convention in all uppercase. To use an enumeration, you would declare a vari- able with that enumeration type and set the value as in the following code:
MailPriority p = MailPriority.REQUIRED_RESPONSE;
Enumerations are much more powerful in Java than in other languages. Although the new keyword isn’t required to instantiate enumerations, they support fields, methods, and constructors. The following code declares the MailPriority enumeration using preset int values: public enum MailPriority {
REQUIRED_RESPONSE (10), REQUIRED_ACKNOWLEDGEMENT(8), OPTIONAL_RESPONSE (4), OPTIONAL_ACKNOWLEDGEMENT (2); //preset value private int relValue; public int getValue() {return relValue;} //constructor public MailPriority (int relValue) {this.relValue = relValue;}
}
Programming in Java122
Built-In Methods for Enumerations
Although enumerations can’t be subclassed, they’re subclasses of the superclass Enum. This means that enumerations include the built-in methods shown in Table 4.
The following code demonstrates how to use these methods:
for(MailPriority p : MailPriority.values()) { System.out.print(“\n” + p.name()); System.out.print(“(“ + p.ordinal() + “) - “); System.out.print(“\”“ + p.toString() + “\”“);
}
The output of the code is as follows:
REQUIRED_RESPONSE(0) - “REQUIRED_RESPONSE”
REQUIRED_ACKNOWLEDGEMENT(1) - “REQUIRED_ACKNOWLEDGEMENT”
OPTIONAL_RESPONSE(2) - “OPTIONAL_RESPONSE”
OPTIONAL_ACKNOWLEDGEMENT(3) - “OPTIONAL_ACKNOWLEDGEMENT”
Note: Because enumer- ations contain discrete values, they can be used in switch statements.
Table 4
Method Description
name() Returns the name of an enumeration constant.
ordinal() Returns the order of an enumeration constant as it was declared.
values() Returns an array of enumeration constants.
Table 4—Built-in Methods
Note: The toString() method is overridden in the Enum class to pro- vide the same value as the name() method.
Lesson 3 123
Self-Check 10
1. What does the phrase “inheritance without the side effects” mean?
__________________________________________________________
2. What are two key differences between abstract classes and interfaces?
__________________________________________________________
3. What is the simple definition of an enumeration?
__________________________________________________________
Check your answers with those on page 205.
Programming in Java124
NOTES
Lesson 3 125
ASSIGNMENT 11: BOXING AND GENERICS Read Assignment 11 in this study guide. Then read Chapter 12, pages 420–426, as well as Chapter 13 in your textbook.
Assignment 11 introduces two important reference type mechanisms: boxing and generics. This study guide covers the selected section in Chapter 12 and Chapter 13. Be sure to complete the Try This activities in Chapter 13, which are invaluable in gaining a more in-depth study of generics.
Type Wrappers
Although primitive types over significant memory and per- formance advantages over objects, you’ll find that certain methods will require an object or you need a primitive value to be modified by a method. The Java language provides spe- cial classes known as type wrappers to allow primitive types to be stored, used, and passed as objects. The following table lists the type wrapper classes and their associated primitive types.
Table 5
Type Wrapper Class Supported Primitive Type
boolean boolean
Byte byte
Short short
Integer int
Long long
Float float
Double double
Character char
Table 5—Type Wrapper Classes
Programming in Java126
All numeric type wrappers are subclasses of the abstract Number class. The Number class provides xxxValue() meth- ods to retrieve a primitive value of any numerical value, whether it’s wrapped by a Byte or Float class. Other features provided by numeric type wrappers include parsing, convert- ing, bitwise manipulation, and display in other representations such as hexadecimal, octal, and binary.
To manually wrap a primitive type, you need only specify the value in the class constructor. The following code demonstrates using a primitive type variable and a literal value:
int primVal = 10; Integer i1 = new Integer(primVal); Integer i2 = new Integer(10);
This process of placing a primitive value into its type wrapper class is known as boxing. The reverse, removing a primitive type from its type wrapper is known as unboxing. The follow- ing code manually unboxes the wrapper objects i1 and i2:
int p1 = i1.intValue(); int p2 = i2.intValue();
Autoboxing
Although you could manually box and unbox primitive types, the runtime does this automatically for you. Any time an operation or method requires an object, the primitive value is boxed. Whenever a primitive value is required by an operation or method, it’s unboxed.
The following code demonstrates this automatic unboxing and boxing for operations:
int result1 = i1 + i2 + 5; //Auto unboxed Integer result2 = p1 + p2 + 5; //Auto boxed
This, of course, works with methods just as easily. If a method requires a subclass of the Object class, for example, then the runtime boxes the primitive value and then automatically unboxes it whenever needed.
Note: As you learned in the previous graded project, the Character class is useful for checking for types of characters, including valid characters for Java identifiers! The Character class also provides methods for offsetting characters and modifying them using character codes.
Lesson 3 127
Note: Autoboxing may seem to be modifying wrapper objects, but like the String object, wrapper objects are immutable. This means that autoboxing can have an impact on performance similar to reassignment with a multitude of String objects. The recommendation is to group together and perform operations with primitive types before assigning the primitive result to a wrapper object.
Generic Objects and Generics
So far you’ve learned how to group objects by either a direct class or superclass. You also know that every object is a sub- class of the Object class. With that knowledge in mind, you want to generalize methods to handle any object by using the Object class. For example, you may want to create a general- ized method for outputting an object’s string representation:
public static void print(Object obj) { System.out.println(obj.toString());
}
This method isn’t necessarily a bad idea, because every class inherits the toString() method. Even if that class doesn’t override the toString() method to display state data, the method will output the class name by default. You might start feeling over-confident and then try something like the following method:
This method is much more problematic. Although all classes inherit the equals() method from the Object class, its default implementation will return true only if both variables reference the same object, not when they’re equivalent. This means the method will work for some pairs of object arguments, but not others.
public static boolean isEqual(Object obj1, Object obj2) { return obj1.equals(obj2);
}
Programming in Java128
Now, another example of over-generalization. You have a method that accepts an array of Object types. Instead of checking first to see what actual types they are, you perform
a cast and then invoke a method not inherited from the Object class. The following code demonstrates this tech- nique:
This is a problem, because some objects may not implement the Movable interface and can’t be casted as such. The com- piler doesn’t know that the cast is invalid, because the actual value for the obj variable isn’t known until runtime. This code will compile, even though it’s possible there will be serious runtime errors. Runtime debugging can consume significantly more time than checking the cast when the code compiles.
The solution is generics. Generics is a category of classes and interfaces that can handle specific parameter types without using the Object class. Because these specific parameter types are checked at compile time, generics provide type safety. Type safety prevents runtime errors when casting.
Generic Methods
When using generics in methods, you can think of them as extra parameters for a method. The only difference is a generic parameter can represent any type and is specified in angle brackets before the return type, not in the parameter list.
public static void moveObjects(Object[] objArray, double time) { for (Object obj : objArray) {
Movable m = (Movable) obj; m.move(time);
} }
public static <T> void moveObjects(T[] genArray, double time) { for (T generic : genArray) { Movable m = (Movable) generic; m.move(time); } }
Lesson 3 129
The following is a generic version of the moveObjects() method:
Now the compiler can track the data type sent to the moveObjects() method using the generic parameter T. Because there are no restrictions on which type T can be, this isn’t altogether helpful. The following modification can restrict T to only those objects that implement the Movable interface:
This modification will now cause the following code to fail compilation before the runtime throws an exception:
String[] strings = {“we”, “do”, “not”, “move!”}; moveObjects(strings, 2.8);
Notice that the code above doesn’t have to specify a generic argument, because the generic argument can be implied by the data type of the first method argument genArray. Since the genArray argument is String array and String objects don’t implement the Movable interface, the code fails compi- lation.
Of course generic types are uncommon, because there’s often an interface or specific class in which objects must implement or extend. In this scenario, we could just as easily support an array of Movable objects which would provide type-safety without generics.
public static <T extends Movable> void moveObjects(T[] genArray, double time) {
for (T generic : genArray) {
Movable m = (Movable) generic;
m.move(time);
}
}
Programming in Java130
For a more in-depth exploration of generics, please read through all of Chapter 13 in the textbook. Because most often you’ll use generic types and not define them, the next activity will have you use the generic collection ArrayList.
Activity 13: Use a Generic Collection
1. Open the Lesson3Activity12.java file of the Lesson3Activity project in NetBeans.
2. Replace the code in the main() method with the following:
3. Build and run the project. The output should match the output at the end of Activity 12.
The big difference between non-generic and generic col- lections is that the programmer isn’t required to perform many casting operations and deal with possible issues at runtime. Using a non-generic ArrayList where every ele- ment was stored as an Object type, was painful in previous versions of Java. Look at the following code for an example of this pain:
ArrayList list = new ArrayList(); list.add(new CameraRobot()); list.add(new Mouse());
for (Object obj : list) ((Movable) obj).printInfo();
Using generic collections, you can be assured that all ele- ments are stored using the data type you need. Although they may seem rather complex at first, generics are a simplification tool.
Note: The diamond operator <> is used when instantiating generic classes that have the generic type already specified in the variable data type. In Java, you don’t need to provide the generic argument twice.
java.util.ArrayList<Nameable> list = new java.util.ArrayList<>();
list.add(new Polygon(“triangle1”, 3, 5));
list.add(new Polygon(“square1”, 4, 3));
list.add(new Polygon(“octagon1”, 8, 10));
list.add(new Polygon(“hexagon1”, 6, 5 ));
list.add(new Circle(“circle1”, 5));
list.add(new Proof(“Congruent triangles”, “ABM and DCM are congruent”,
“AD bisects BC”, “BC bisects AD”));
for (Nameable n : list) n.printInfo();
Lesson 3 131
Self-Check 11
1. How are type wrappers used in Java?
__________________________________________________________
2. What is autoboxing?
__________________________________________________________
3. Given the following method declaration, which type of objects are allowed for the array and elem parameters?
<T extends Comparable<T>> void sortArray (T[] array, T elem)
__________________________________________________________
__________________________________________________________
Check your answers with those on page 205.
Programming in Java132
NOTES
133
G ra
d e
d P
ro je
c t
G ra
d e
d P
ro je
c t
Object-Oriented Programming
OVERVIEW
After reading selected sections of Chapters 4, 6, 7, 8, 12, and 13 in the textbook and completing Lesson 3, you’re ready to begin object-oriented programming. This project will assess your understanding of creating a class hierarchy in a package and writing code for classes and enumerations.
Make sure that you follow all directions completely and verify your results before submitting the project. Remember to include all required components in your solution.
YOUR PROJECT
In this project, you’ll create data types in a class structure for cell-based board games similar to Tic-Tac-Toe. Games like Connect Four and Mastermind also use boards divided by rows and columns. The Board and Cell classes represent the board, while the Player, Mark, and Outcome enumerations track the game.
You’ll use the classes and enumerations created in this project in future graded projects. You use the NetBeans project in the next lesson.
INSTRUCTIONS
1. In NetBeans, create a new Java Application project named BoardGameTester.
2. Create a new package named games and a sub-package of games named board. The easiest way is simply to create a package named games.board.
Graded Project134
3. Add an enumeration named Player to the games.board package. You could add Empty Java File or choose Java Enum as the file type. This enumeration represents the current player in a turn-based game. Use the follow- ing code:
public enum Player {FIRST,SECOND}
Note: Although Tic-Tac-Toe and Mastermind allow only two players, Connect Four can be played with up to four players. For simplicity, our code will handle only two players.
4. Add an enumeration named Outcome to the games.board package. This enumeration represents the result when the turn is completed. Use the following code:
5. Add an enumeration named Mark to the games.board package. This enumeration represents the result when the game is completed. Use the following code:
Note: Yellow and red are used in Connect Four, while Mastermind uses all six colors.
6. Add the Cell class to the games.board package. It should have the private variables content, row, and column, and the public methods getContent, setContent, getRow, and getColumn. Use the following code as a guide:
public class Cell { private Mark content; private int row, column;
public Cell(int row, int column) { this.row = row; this.column = column;
content = Mark.EMPTY; } public Mark getContent() { return content; }
public enum Outcome {PLAYER1_WIN, PLAYER2_WIN, CONTINUE, TIE}
public enum Mark {EMPTY, NOUGHT, CROSS, YELLOW, RED, BLUE, GREEN, MAGENTA, ORANGE}
Graded Project 135
Note: All classes that support direct instantiation should have a constructor. In this case, the constructor will be used by the Board class to create each of its cells.
7. Add the Board class to the games.board package. It should have a two-dimensional array of Cell objects. The Board class should initialize a board with a specified number of columns and rows, provide access to Cell objects, and display all of its cells correctly. Use the following code as a guide:
public class Board { private Cell[][] cells;
public Board(int rows, int columns) { cells = new Cell[rows][columns]; for( int r = 0; r < cells[0].length; r++ ) {
for (int c = 0; c < cells[1].length; c++) { cells[r][c] = new Cell(r,c);
} }
} public void setCell(Mark mark, int row, int column) throws IllegalArgumentException {
if (cells[row][column].getContent() == Mark.EMPTY) cells[row][column].setContent(mark);
else throw new IllegalArgumentException(“Player already there!”); } public Cell getCell(int row, int column) { return cells[row][column];
} public String toString() {
StringBuilder str = new StringBuilder();
for( int r = 0; r < cells.length; r++ ) { str.append(“|”); for (int c = 0; c < cells[r].length; c++) {
switch(cells[r][c].getContent()) {
public void setContent(Mark content) { this.content = content; } public int getRow() { return row; }
public int getColumn() { return column; } }
Graded Project136
case NOUGHT: str.append(“O”); break;
case CROSS: str.append(“X”); break;
case YELLOW: str.append(“Y”); break;
case RED: str.append(“R”); break;
case BLUE: str.append(“B”); break;
case GREEN: str.append(“G”); break;
case MAGENTA: str.append(“M”); break;
case ORANGE: str.append(“M”); break;
default: //Empty str.append(“ “);
} str.append(“|”);
} str.append(“\n”);
} return str.toString();
}
}
Note: This code should seem familiar to you. The meth- ods in the TicTacToeGame class are similar to those in the Board class. The StringBuilder class was used instead of the String class for better performance. You can learn more about the StringBuilder class by visiting the Oracle Website at http://docs.oracle.com/javase/ tutorial/java/data/buffers.html.
Graded Project 137
8. Add the following import statement to the BoardGameTester class:
import games.boards.*;
9. In the main() method of BoardGameTester, perform the following actions:
a. Create a 3 × 3 board for a Tic-Tac-Toe game.
b. Create a 6 × 7 board for a Connect Four game.
c. Create a 5 × 8 board for a game of Mastermind.
d. Set a cell to a nought or cross on the Tic-Tac-Toe board.
e. Set a cell to yellow or red on the Connect Four board.
f. Set a cell to yellow, red, green, blue, magenta, or orange on the Mastermind board.
g. Display the boards for Tic-Tac-Toe, Connect Four, and Mastermind.
10. Compile and run the project to ensure it works as expected.
SUBMISSION GUIDELINES
To submit your project, you must provide the following source code files in a ZIP file:
■ BoardGameTester.java
■ Board.java
■ Cell.java
■ Mark.java
■ Outcome.java
■ Player.java
Graded Project138
To find these files within NetBeans, go to the BoardGameTester project folder. To determine this folder, right-click on BoardGameTester project in the Projects panel. Copy the value for the Project Folder textbox using the keyboard shortcut CTRL+C. In Windows Explorer, paste the project folder path and hit the ENTER key. Right-click on the src folder and choose the Send to... > Compressed (zipped) folder option from the context menu. Rename the file to BoardGameTester_Lesson3.zip and copy it to your desk- top or any other temporary location.
Follow this procedure to submit your project online:
1. Log on to the Penn Foster website and go to My Courses.
2. Click Take Exam.
3. Attach your Zip file as follows:
a. Click on the Browse box.
b. Locate the file you wish to attach.
c. Double-click on the file.
d. Click Upload File.
4. Enter your e-mail address in the box provided. (Note: This information is required for online submissions.)
5. If you wish to tell your instructor anything specific regarding this assignment, enter it in the Message box.
6. Click Submit File.
Grading Criteria
Your instructor will use the following guidelines to grade your project.
All types are organized in correct package hierarchy 10 points
Mark enumeration correctly defined 5 points
Outcome enumeration correctly defined 5 points
Player enumeration correctly defined 5 points
Cell class correctly defined 10 points
Board class correctly defined 10 points
BoardGameTester class correctly defined 20 points
The application returns expected output 25 points
All source code files are included: 10 points
TOTAL 100 points
Graded Project 139
NOTES
Graded Project140
141
L e
s s
o n
4 L
e s
s o
n 4
Advanced Programming Logic
INTRODUCTION
So far the applications you’ve designed are transient and unoptimized. They’re effective as long as a user keeps the program running and performs one action at a time. Well- built applications usually take advantage of a user’s local storage and memory/CPU utilization. In this lesson, you’ll learn how to load and save data to files and use multithread- ing techniques to improve the consistency and performance of your applications.
OBJECTIVES
When you complete this lesson, you’ll be able to
■ Differentiate between the I/O classes provided by Java
■ Write data from an application to a file
■ Read data from a file back into an application
■ Access the local user’s file system using the java.nio package
■ Create a custom thread using the Thread class and Runnable interface
■ Control a running thread’s lifetime and priority
■ Use thread synchronization and notification techniques
■ Use the java.util.concurrency package
Programming in Java142
ASSIGNMENT 12: USE I/O CLASSES Read Assignment 12 in this study guide. Then read Chapter 10 in your textbook.
Assignment 12 introduces basic input/output programming in Java and addresses the new I/O classes provided by Java 7 in the java.nio package. Be sure to complete the Try This activities in Chapter 10.
Standard Stream Classes
A stream is a sequential flow of data from a source to a destination. Sources can include files, network hosts, or even local String objects. Data sent through a stream can be raw bytes, individual characters, sequences of characters, or entire objects. Input streams read data from a stream, while output streams write data to a stream.
There are many stream classes located in the java.io pack- age, each specialized for certain types of streams, sources, and destinations. In the textbook, Table 10-1 on page 328 lists all of the byte stream classes, while Table 10-2 on page 329 lists all of the character stream classes. The fundamental difference between byte and character streams is that character streams convert bytes into characters. Byte streams don’t assume a character set and are intended for images, object serializations, and other binary data.
Byte Streams
Byte input and output streams are subclasses of the abstract classes InputStream and OutputStream, respectively. The core method of the InputStream class is read(). The read() method can retrieve a single byte or an array of bytes. When the end of the stream is reached, read() will return -1. The core method of the OutputStream class is write() and can also handle a single byte or array of bytes. The OutputStream class includes the flush() method to push buffered data into the stream. Both InputStream and OutputStream provide a close() method to end the stream and release all system resources used by that stream.
Lesson 4 143
The following code demonstrates a common algorithm used in reading byte streams:
while ( (byteRead = inputStream.read() ) != -1) { //do something with the bytes here
}
As you can see from this example code, the while and do- while statements are prominent in I/O programming. Notice also from this example that the read() method is invoked, then immediately assigned, and compared to -1. This condi- tion will ensure the block ends once the end of the stream is reached.
Character and Buffered Streams
Character input and output streams are subclasses of the abstract classes Reader and Writer, respectively. The Reader class also provides the read() method, but unlike the InputStream class, the Reader retrieves converted char values from the stream. The Writer class provides a write() method for characters, but also includes the append() method for adding characters to the end of a stream. The flush() method pushes buffered characters into the stream. Like InputStream and OutputStream, the Reader and Writer classes provide a close() method.
Because character streams merely convert between bytes and characters, character stream classes accept byte streams for their constructors. By wrapping a byte stream in a character stream, you can take advantage of sources and destinations that don’t natively support character conversion. The follow- ing code wraps the standard input byte stream with a character stream:
Reader reader = new InputStreamReader( System.in );
Often, you’ll need to read characters, not one at a time, but entire lines at a time. BufferedReader is a wrapper for Reader objects to provide the additional readLine() method. The PrintWriter is a wrapper for Writer objects to provide the additional println() and printf() methods. The printf() method is intended for formatting an array of objects in a
Note: Both byte and character stream classes can throw an IOException. If a method throws an IOException, then you must either handle the exception in a try/catch block within the method or declare that method throws an IOException.
Programming in Java144
String. You can read more about formatting string syntax in the Java 7 API Documentation at http://docs.oracle.com/ javase/7/docs/ api/java/util/Formatter.html#syntax
System Streams
In using the command line for I/O operations, you’ve already been exposed to predefined streams provided by the System class:
■ System.in—Standard keyboard entry using the InputStream class
■ System.out—Standard text-based output using the PrintStream class
■ System.err—Standard text-based output formatted for errors using the PrintStream class
Another technique for using the command line is to use the Console class. If you develop command-line applications, you should use the Console class rather than the System streams. Unfortunately, the Console class isn’t compatible with the Output pane in the NetBeans IDE.
Opening and Closing Streams
To open a stream for reading or writing in Java, you need only instantiate the stream class. The available() method in the InputStream class will return the number of bytes available for reading. The ready() method returns a boolean indicating whether the stream is available for reading with the Reader class.
Note: Byte streams have a class similar to PrintWriter. The PrintStream class also provides the println() and printfs() methods.
Lesson 4 145
When reading or writing with the stream is complete, that stream should be closed and its pointer dereferenced. The following code performs this action manually:
Note: The finally block will execute whether or not an excep- tion is thrown. However, if the close() method throws an exception, then any exceptions thrown from the try block will be effectively suppressed. The Throwable class provides getSuppressed() and initCause() to access suppressed excep- tions in these situations.
Java 7 introduces a new construct to handle this logic seamlessly. The try-with-resources statement will automati- cally close and dereference resources that implement the AutoCloseable interface. All stream classes implement this interface, so this construct can definitely simplify your code.
The previous example could be rewritten using the try-with- resource statement:
try ( FileWriter fs = new FileWriter(“output”) ) { //perform write operations
} catch (IOException ex) { //handle exception
}
try { FileWriter fs = new FileWriter(“output.txt”); //perform write operations } catch (IOException ex) {
//handle exception } finally {
if (fs != null ) { // <- instantiation may have failed fs.close(); // <- close the stream fs = null; // <- dereference the stream pointer
} }
Programming in Java146
Reading and Writing to Files
To read from a file, you can use the byte stream FileInputStream or character stream FileReader. To write to a file, you can use the byte stream FileOutputStream or character stream FileWriter. The constructors for these classes can accept a path name or legacy File object. These constructors can throw FileNotFoundException if the loca- tion is invalid or SecurityException if the current user doesn’t have permission to read or write to it.
The following code copies a file byte into another file:
In the next activity, you’ll use the ObjectInputStream and ObjectOutputStream classes to write and read an object and use the FileInputStream and FileOutputStream classes to read and write that object to a file.
Activity 14: Read and Write Objects with a File
1. Create a new Java Application project named Lesson4Activity14 in NetBeans.
2. Create a new public class named Employee to the Lesson4Activity14 package.
3. Inside the Employee class, add the following code:
Note: For an object to be written to a stream, it must implement the Serializable interface. All fields, including those declared as private, are written to the stream.
Note: The readObject() method throws a ClassNotFoundException, because the object may represent a class that’s unavailable to the application.
try (
FileInputStream fsIn = new FileInputStream(“input.txt”); FileOutputStream fsOut = new FileOutputStream(“output.txt”)
) { int b; while ( (b = fsIn.read()) != -1 )
fsOut.write(b); } catch (IOException ex) {
System.err.println(ex.toString()); }
Lesson 4 147
4. Open the Lesson4Activity14.java file. You can do this by either clicking its tab at the top of Documents because it should be open or by double-clicking the Lesson4Activity14.java file in the Projects pane.
5. Make sure you add import the java.io package in the Lesson4Activity14.java file using the following statement:
import java.io.*;
6. Add the following code in the main() method:
7. Build and run the project. The output should be as follows:
Employee object written to file. Employee object read from file. 999-99-9999 (Joshua Hester) - Developer.
//Activity 14 Employee emp = new Employee(“Joshua Hester”, “999-99-9999”, “Developer”);
//save employee to file try (FileOutputStream fout = new FileOutputStream(“emp.data”);
ObjectOutputStream objout = new ObjectOutputStream(fout);) { objout.writeObject(emp); objout.flush(); System.out.println(“Employee object written to file.”); } catch (IOException ex) { System.err.println(ex); }
emp = null; //clear employee
//read back employee from file try (FileInputStream fin = new FileInputStream(“emp.data”); ObjectInputStream objin = new ObjectInputStream(fin);) { emp = (Employee) objin.readObject(); System.out.println(“Employee object read from file.”); } catch (IOException | ClassNotFoundException ex) { System.err.println(ex); } System.out.println(emp);
Programming in Java148
New I/O Classes
Although the system.io package provides classes, enumera- tions, and interfaces to handle local file system viewing and manipulation, Java 7 introduced a new file I/O mechanism in the java.nio package. The java.nio package offers signifi- cant advantages over the older java.io package. Not only are file I/O operations with java.nio greatly simplified, but this mechanism utilizes memory buffers, read/write channels, and multiple threads.
Table 6 lists common I/O classes and interfaces in the java.nio package and java.nio.file and ava.nio.file.attribute subpackages.
Note: Many of these classes are abstract, because the JVM provides the implemen- tation optimized for the target file system at runtime. This means that file I/O operations should work regardless of which operating sys- tem is installed.
Table 6
Class Description
Buffer Abstract sequence of primitive elements storedfor an underlying stream
MappedByteBuffer An abstract byte-portion of a file mapped to memory
FileChannel An abstract channel for file reading/writing and manipulation
NetworkChannel An interface for channels using network protocols
SocketChannel, ServerSocketChannel Abstract network channels that represent clientsenders and server listeners, respectively
Path Interface that represents a file/directory location on the file system. To get a Path object, use the Paths class.
DirectoryStream Interface used to iterate through entries in a directory
Files A class that provides static methods for opening, Table 6—Java.nio classes
Lesson 4 149
You’ll use a Path object to reference a file or directory loca- tion. The Paths class provides the static method get(), which can accept one or more String arguments. The following code demonstrates how to access a File using the Paths class:
Path p1 = Paths.get(“file.txt”); //relative Path p2 = Paths.get(“C:\\Java\\file.txt”); //absolute Path p3 = Paths.get(“C:”, “Java”, “file.txt”); //same as p2 boolean isSameFile = Files.isSameFile(p2, p3); //set to true
Assuming the current compiled class is in the same location as file.txt, all three of these Path objects would reference the same file. When using absolute locations, the last code state- ment is the preferred convention. This is because the JVM automatically adds the path separator (\ for Windows; / for Linux, Unix, and Mac) for the target OS. It’s always prefer- able to be agnostic in terms of the OS, so that your Java application will run on any platform.
A Path object doesn’t map to an actual file or directory location, because a path may not exist on the local file system. This is helpful for creating new files, but can complicate matters when reading from or appending to an existing file. Before using a Path object for input, you should invoke either the exists() or notExists() method on the Files class. If the file system can’t confirm its existence because of a hardware or driver issue, then it may return false for both methods.
The Files class also provides methods to verify the capabili- ties of the file. The isReadable() and isWritable() methods are important to check before attempting to open a file. The StandardOpenOptions enumeration specifies how the file should be opened when performing write operations. This enumeration includes the following fields:
1. WRITE—Write access.
2. APPEND, TRUNCATE_EXISTING—Add data to the end of the file or overwrite existing data, respectively.
Note: You can use the getPath() method on the default FileSystem object to retrieve a Path object. Also, the FileSystem object provides helpful OS- specific methods to ensure that your file I/O code remains agnostic of the OS. These methods include getSeparater() and getRootDirectories().
Note: The StandardOpenOptions enumeration fields use the bitwise OR operator | to combine values.
Programming in Java150
3. CREATE, CREATE_NEW—Create a new file. CREATE will open the file if it already exists, while CREATE_NEW will throw an exception if the file already exists.
4. DELETE_ON_CLOSE—Deletes the temporary file after I/O operations are complete.
When handling files, you’ll most often use Files and/or Path to access a file for reading or writing. The simplest method is to use the self-explanatory methods readAllBytes() or readAllLines() or write(). This is appropriate for small files less than a megabyte in size. Larger text files can retrieve buffered streams using the newBufferedReader() and newBufferedWriter() methods. For backwards compatibility, the methods newInputStream() and newOutputStream() are provided, but the newByteChannel() method is intended for larger data files. Finally, the most robust and complex mech- anism for accessing files is using FileChannel, which offers file-locking features, file bytes to memory mapping, and advanced reading and writing controls.
The following code reads all bytes from one file and copies those bytes into another:
In Activity 15, you’ll use buffered streams to write and then read back contents of a file.
Path srcFile = Paths.get(“original.txt”); Path destFile = Paths.get(“copy.txt”); try {
byte[] readBytes = Files.readAllBytes(srcFile); //read Files.write(destFile, readBytes); //write
} catch (IOException ex ) { System.err.println(ex.toString());
}
Lesson 4 151
Activity 15: Use New I/O Classes to Read and Write Files
1. Open the Lesson4Activity14 project in NetBeans.
2. Open the Lesson4Activity13.java file.
3. Make sure to add the following statements to the Lesson4Activity13.java file:
import java.nio.*; import java.nio.file.*; [program font ends here]
4. So that you can keep the code used in Activity 13 for fur- ther reference without affecting this activity’s code, you’ll comment the current code. To do this, highlight the cur- rent code in the main() method and then choose the Toggle Comment option from the Source menu or the keyboard shortcut CTRL+/.
5. Add the following code to the main() method as follows:
//Activity 15
Path file = Paths.get(“activity.txt”);
Charset cset = Charset.forName(“UTF-16”);
if (Files.notExists(file)) { //Check for file
System.out.println(“Enter text for new file. Hit ENTER on a blank line to end.”);
try (BufferedReader stdin = new BufferedReader( new
InputStreamReader(System.in));
BufferedWriter fout = Files.newBufferedWriter(file, cset);) {
String line = ““;
while ((line = stdin.readLine()) != null && line.length() != 0 ) {
fout.write(line);
fout.newLine();
}
fout.flush();
} catch (IOException ex) {
System.err.println(ex);
}
System.out.println(“File written.”);
} else {
System.out.println(“Reading file ....”);
try (BufferedReader fin = Files.newBufferedReader(file, cset);) {
String line = ““;
Programming in Java152
This code checks to see if a file doesn’t exist. If the file doesn’t exist, then it creates the file by reading each line from the command line and writing it to the file. If the file does exist, then the contents of the file are read line- by-line and printed as output.
6. Build and run the project. You should be prompted to write the contents of the file. You can write as many lines of text as you like. When you’re done, hit the ENTER key on a blank line to finish writing to the new file.
7. Run the project again. Because the file was already written, the contents of the file should be displayed.
while ((line = fin.readLine()) != null) {
System.out.println(line);
}
} catch (IOException ex) {
System.err.println(ex);
}
}
Lesson 4 153
Self-Check 12
1. What are the differences between byte, character, and buffered streams?
__________________________________________________________
2. Which standard method is used to retrieve data from a stream? Which standard method is used to modify data in a stream?
__________________________________________________________
3. Which three predefined streams accept standard input and generate output and errors?
__________________________________________________________
4. How does the try-with-resources statement handle resource objects?
__________________________________________________________
5. Which interface in the java.nio package represents the location of a file or directory?
__________________________________________________________
Check your answers with those on page 205.
Programming in Java154
ASSIGNMENT 13: USE MULTIPLE THREADS Read Assignment 13 in this study guide. Then read Chapter 11 in your textbook.
Assignment 13 introduces multithreading concepts and how to use threads in Java as well as high-level threading classes. Be sure to complete the Try This activities in Chapter 11. It’s highly recommended that you read the Concurrency lesson in the Oracle Java Tutorials at http://docs.oracle.com/ javase/tutorial/essential/concurrency/ before implementing multithreading in any professional applications.
Threading Basics
A process is a unique runtime environment for a running application. Each process contains its own state, memory address, and set of resources. Processes can communicate with each other, but not through direct memory access. These communication mechanisms are controlled by the operating system, not the programmer.
A thread is a distinct task performed by an application. Threads can share state and memory, because they’re exe- cuted within the same process. Whereas multiple processor cores dictate how many concurrent processes can execute, application code dictates how many concurrent threads can execute in a process.
It’s important to note that neither multiprocessing operating systems nor multithreaded applications execute their units exactly at the same time. There’s a system of scheduling required, where each execution unit, whether a thread or process, is assigned a slice of time in which to be active. The execution is active until the time expires; it completes or a higher priority unit requires access. In the case of processes, the operating system controls access to hardware resources. In the case of Java threads, it’s the JVM that controls execution scheduling and execution.
Lesson 4 155
Creating Threads
By default, all Java applications have a single user thread known as main. As you recall, the main() method is the first point of entry for a Java application. All execution in the main() method is executed on the main thread. Even when code outside the main() method is executed, the main thread is used, because the invocations originate from within the main() method. Thus, all applications you’ve developed so far are single-threaded.
To create custom threads, you can either implement the Runnable interface or extend the Thread class because the Thread class implements the Runnable interface. Explicitly implementing the Runnable interface is preferred, but you’ll still use the Thread class to start and control the thread. The table at the bottom of page 369 in Chapter 11 of the textbook lists the most common Thread methods. The body for a thread is defined within its run() method. The run() method often performs long-running calculations or complex iterative algorithms. The run() method must match the following signature:
public void run()
The following code creates a thread class by implementing the Runnable interface:
public class ThreadWithRunnable implements Runnable {
public void run() {
//perform work
}
}
Note: Because the run() method can’t accept arguments or return values, input and out- put is handled by sharing fields between threads. The Callable interface is more flexible with its call() method, which can return a value.
Programming in Java156
The following code creates a thread class by extending the Thread class:
public class ThreadWithThreadClass extends Thread {
public void run() { //perform work
} }
The real difference between these two techniques is overhead and how the thread is started. To start a thread, you must use the start() method of the Thread class. If the custom thread class extends Thread, then you need to instantiate only the Thread class and invoke start(). If the custom thread class implements Runnable, then you need to instan- tiate the custom thread class, specify the thread object in the Thread class constructor, and then invoke the start() method.
The following code demonstrates how to start threads using both techniques:
//thread instantiation Thread thRunnable = new Thread(new ThreadWithRunnable()); Thread thThreadClass = new ThreadWithThreadClass(); //start the threads thRunnable.start(); thRunnable.start();
Thread Lifetime
Figure 9 depicts the states in a thread’s lifetime.
As indicated in the lifetime, the start() method doesn’t actu- ally run the thread, but places it in the runnable queue. For most threads, the majority of their lifetime is spent in the runnable state. When a thread actually runs is determined by the scheduler based on its priority and position in the queue. A higher priority thread is more likely to receive exe- cution time than a lower priority thread. In many cases, a high-priority thread can dominate execution if other threads
Note: Although the run() method contains the main body of a thread, it’s actually the start() method that executes the body on a separate thread.
Lesson 4 157
in the runnable queue are low-priority. To set a thread’s pri- ority, you can use the setPriority() method. The default priority level is NORM_PRIORITY, with both MIN_PRIORITY and MAX_PRIORITY as the other options.
A thread can move from running back into the runnable state by using the yield() method. The yield() method notifies the scheduler that a thread is willing to give up execution time for other runnable threads. Unfortunately, the exact implemen- tation differs by operating system. In Windows, the thread is forced to wait a specified amount of time, but then can immediately resume its execution later. In Linux, the thread is forced to wait until all other threads in the queue execute at least once.
From the running state, a thread can also move into the blocked and dead state. A thread in the blocked state is effectively paused, waiting in memory for immediate execution. Like runnable, the blocked state uses a queue for waiting threads. The operating system can interrupt a thread if a runtime exception occurs or a higher priority thread requires execution. The sleep() method moves a thread into the blocked state for a predetermined number of milliseconds. After the time has elapsed, the thread is pushed into the wait queue for immediate execution.
FIGURE 9—A Thread’s Lifetime
Programming in Java158
The join() method is a bit more complex. When Thread1 invokes the join() method on Thread2, Thread1 will be blocked until Thread2 is dead. A thread is considered dead if that thread completes its work or is stopped manually by the programmer or operating system. The isAlive() method indi- cates whether a thread is in any other state than dead. Remember that a thread is alive when it’s in the runnable queue or blocked.
Activity 16: Create and Control a Custom Thread
1. Create a new Java Application project named Lesson4Activity16 in NetBeans.
2. Create a new public class named Timer to the lesson4Activity16 package.
3. Inside the Timer class, add the following code:
public class Timer implements Runnable { private boolean stopped; private long delay;
public Timer (long delay) { this.delay = delay;
} public void stop() { stopped = true; } public void run() { while (! stopped ) {
java.util.Date time = new java.util.Date(); System.out.println(time); for (long i = 0; i < delay; i++);
} } }
This class is a simple timer that outputs the current time in a thread. The stop() method ends the timer.
4. Open the Lesson4Activity16.java file. You can do this either by clicking its tab at the top of Documents because it should be open or by double-clicking the Lesson4Activity16.java file in the Projects pane.
Lesson 4 159
5. Add the following code in the main() method:
6. Build and run the project. The timer should display until you hit the S key and ENTER. The only reason this works is because the timer is displaying output on a separate thread from the main thread, which is listening for input.
Code Synchronization
For threads to communicate, they must share fields and object references with each other. When multiple threads share data like this, error conditions such as thread interference and memory inconsistency can occur. In thread interference, two or more operations running in different threads act on the same data and overlap their sequence of execution. Thread interference errors are difficult to detect, because the results are unpredictable. Memory inconsistency occurs when multi- ple threads see the same data differently. For example, while Thread1 is incrementing a counter variable, Thread2 may be reading the previous value and assuming it’s the current value.
To prevent these error conditions, you can use the synchro- nized keyword. The synchronized keyword can lock a block of statements or entire method, so that only one thread at a time can execute. When using the synchronized keyword
Timer tmr = new Timer(1_000_000_000); System.out.println(“Timer started. \’s\’ to stop”); new Thread(tmr).start();
while (true) { try { if (System.in.read() == ‘s’) {
tmr.stop(); break;
} } catch (java.io.IOException ex) { System.err.println(ex); } }
System.out.println(“Timer stopped.”);
Note: By default, each thread stores a copied value from a shared field. A field declared with the volatile key- word will allow all threads to use a master copy of value. If a field is bound to change often in multithreaded situations, you may find more consistent results by using the volatile keyword.
Programming in Java160
with a block of statements, you choose an object that repre- sents the lock. This usage of the synchronized keyword is known as a synchronized statement. In most cases, the lock is the current object modified by the group of statements.
The following code demonstrates a synchronized statement:
synchronized(this) { this.counter++;
}
When using the synchronized keyword with a method, only a single thread can execute the method at a time. This means that method invocations by other threads are blocked until the current thread returns from the method. This type of method is known as a synchronized method.
The following code demonstrates a synchronized method:
public synchronized void increment(int value) { this.counter += value;
}
When using synchronized statements and methods, you can take advantage of thread-related methods provided by the Object class. An overloaded version of the wait() method takes no argument and will move a thread into the blocked state until it’s notified to resume. By default, this will move the thread directly into the wait queue rather than having a timeout. The notify() method will resume a single thread from the wait queue. The resumed thread will be the first thread in the queue. The notifyAll() method will attempt to resume all threads in the queue, so that the highest priority thread will resume first.
A simple threading model that utilizes these methods is producer/consumer. The producer provides a resource that’s used by the consumer. A consumer thread invokes a wait() on itself to allow the producer to prepare access to the resource. When the resource is available, the producer thread then invokes the notify() or notifyAll() methods. When the consumer thread completes, it can then wait again until resources are made available by the producer thread.
Lesson 4 161
High-Level Concurrency
If manual threading seems too complex to implement large-scale, don’t worry. Java offers high-level locking, thread pools, and concurrent-safe collections to simplify multithreaded applications. These types are found in the java.util.concurrent package.
Table 7 lists these high-level concurrency types.
Table 7
Class Description
Lock An interface that allows explicit control for tryingto acquire and releasing a single-thread lock
ReadWriteLock An interface that allows one lock to be shared by reader threads and another exclusive lock for writer methods
Callable An interface implemented by threads which canreturn a value
RecursiveTask Abstract class that represents a task that can bedivided into recursive invocations
Future This interface represents the result from anasynchronous invocation
ExecutorService An interface for executing threads within automated thread pools
ScheduledExecutorService An interface for executing threads at set delayand/or repeated period
BlockingQueue, ConcurrentMap, ConcurrentMap
Interfaces implemented by collections that protect elements when multiple threads access those elements concurrently
Table 7—High-level Concurrent Classes
Programming in Java162
The following code demonstrates usages of high-level concur- rency classes and interfaces:
This code generates a random number after a 10-second delay.
public class CalcThread implements Callable { //Callable implementation public Integer call() throws Exception {
//Get number from 1 to 10 return ThreadLocalRandom.current().nextInt(1,11);
} public static void main(String[] args) {
ScheduledExecutorService ex = Executors.newScheduledThreadPool(1);
Callable c = new CalcThread(); Future f = ex.schedule(c, 10, TimeUnit.SECONDS); while (!f.isDone()) {} //waiting try {
System.out.println(f.get()); ex.shutdown();
} catch (Exception e) { System.err.println(“Error: “ + e.toString());
} }
}
Lesson 4 163
Self-Check 13
1. How does a thread differ from a process?
__________________________________________________________
2. What are the two techniques for creating a custom thread class?
__________________________________________________________
3. How do the Runnable and Callable interfaces differ?
__________________________________________________________
4. What is the initial state of a thread after the start() method is invoked?
__________________________________________________________
5. What does the synchronized keyword allow?
__________________________________________________________
Check your answers with those on page 206.
Programming in Java164
NOTES
Lesson 4 165
Advanced Programming Logic
OVERVIEW
Now you’re ready to add file I/O to your board game applica- tion. This project will assess your understanding of writing a file and using multithreading.
Make sure to follow all directions completely and verify your results before submitting the project for grading. Remember to include all required components in your solution.
YOUR PROJECT
In this project, you’ll modify the BoardGameTester application to save the gameboard to a file. You’ll perform the file writing process on a separate thread.
INSTRUCTIONS
1. In NetBeans, open the BoardGameTester project.
2. Create a new package named games.utilities.
3. Add a public class named FileManager that contains the following methods:
public static void writeToFile(String saveState, String
fileName) {
//TODO: Write a string to a new file synchronously
}
public static void writeToFileAsync(final String saveState,
final String fileName) {
//TODO: Write a string to a new file asynchronously
}
G ra
d e
d P
ro je
c t
G ra
d e
d P
ro je
c t
Programming in Java166
4. Implement the writeToFile method using the new file I/O classes in a try-with-resources statement.
Note: Use the code in Activity 15 as a guide for the writeToFile method. Remember to import the java.io, java.nio, java.nio.charset, and java.nio.file packages.
5. Implement the writeToFileAsync method using a sepa- rate thread. Use the following code as a guide:
new Thread() { public void run() { writeToFile(saveState, fileName); } }.start();
Note: This code uses an anonymous inner class to declare and instantiate a Thread class. Unlike a traditional inner class, anonymous inner classes are available only within the statement they’re declared. You’ll see more examples of anonymous classes with Swing in the next lesson. To ensure that local variables are unchanged by the inner class, the parameters saveState and fileName must be declared with the final keyword.
6. In the main() method of the BoardGameTester project, add the following code:
Note: Remember to import the games.utilities package!
7. Compile and run the project to create three files, one for each saved board game. Open the files to ensure they contain the correct game board display.
Note: Notepad won’t display the line returns in the file. You may need to open the text files using Microsoft Word or Wordpad instead.
These three game board files will be required for submission.
FileManager.writeToFileAsync(ticTacToe.toString(), “ttt.txt”); FileManager.writeToFileAsync(connectFour.toString(), “c4.txt”); FileManager.writeToFileAsync(mastermind.toString(), “mm.txt”);
Lesson 4 167
SUBMISSION GUIDELINES
To submit your project, you must provide the following source code files in a ZIP file:
■ BoardGameTester.java
■ FileManager.java
■ ttt.txt
■ c4.txt
■ mm.txt
To find the Java source files within NetBeans, go to the BoardGameTester project folder. To determine this folder, right-click on BoardGameTester project in the Projects panel. Copy the value for the Project Folder textbox using the keyboard shortcut CTRL+C. In Windows Explorer, paste the project folder path and hit the ENTER key. Copy both the BoardGameTester.java file from the src\boardgametester folder and the FileManager.java file from the src\games\utilities folder to your desktop or any other tem- porary location. The three game board files will be located at the root of the project folder.
Follow this procedure to submit your project online:
1. Log on to the Penn Foster website and go to My Courses.
2. Click Take Exam.
3. Attach your zip file as follows:
a. Click on the Browse box.
b. Locate the file you wish to attach.
c. Double-click on the file.
d. Click Upload File.
4. Enter your e-mail address in the box provided. (Note: This information is required for online submissions.)
5. If you wish to tell your instructor anything specific regarding this assignment, enter it in the Message box.
6. Click Submit File.
Programming in Java168
GRADING CRITERIA
Your instructor will use the following guidelines to grade your project.
FileManager class correctly defined 40 points
BoardGameTester class correctly modified 20 points
All three game board files are correct 20 points
All source code and files are included: 20 points
TOTAL 100 points
Lesson 4 169
Graphical User Interface Design
INTRODUCTION
So far you’ve focused on developing command-line applications that strictly control text-based input/output. Most modern applications use a graphical user interface (GUI) for input/ output and rely on user events to perform their operations. In this lesson, you’ll be introduced to the APIs for the abstract windowing toolkit (AWT), Swing, and JavaFX. After completing this lesson, you’ll be prepared to create robust and user- friendly applications in Java!
OBJECTIVES
When you complete this lesson, you’ll be able to
■ Discuss Java applet technology and life cycle
■ Create and use a Java applet
■ Use the Graphics class to paint text and basic shapes
■ Register and handle standard events
■ Differentiate Swing from the abstract windowing toolkit (AWT)
■ Explain the model-view-controller pattern
■ Use layout managers to organize Swing components
■ Create and add standard Swing components
■ Create an applet with Swing
■ Describe JavaFX technology
L e
s s
o n
5 L
e s
s o
n 5
Programming in Java170
ASSIGNMENT 14: CREATE APPLETS AND HANDLE EVENTS Read Assignment 14 in this study guide. Then read Chapter 14, pages 473–496, as well as Chapter 15, pages 536–537, in your textbook.
Create Applets and Handle Events
Assignment 14 introduces applets and event handling using AWT, and covers anonymous inner classes, which are presented in Chapter 15. Be sure to complete the Try This activities in Chapter 14.
Applet Basics
An applet is a small GUI application embedded in a Web page. Applets are often built as executable Java archive (JAR) files and are executed by the JVM associated with a brower’s plug-in manager. Because applets are automatically loaded by the browser, Java applets run in security sandbox to pro- tect the client OS from malicious code. Unsigned applets are those that aren’t signed with a valid certificate from a trusted certificate authority (CA). They can’t access the local file sys- tem or other remote Web servers. Signed applets can run in standalone mode and are limited only by general OS security.
Applets are embedded in Web pages in the same way as other multimedia is. In earlier versions of HTML, you would use the <applet> element, while the <object> element is preferred for HTML5. The following HTML embeds an applet in a Web page:
<object type=“application/x-java-applet” width=“800” height=“600”>
<param name=“code” value=“AppletClass” /> <param name=“archive” value=“Applet.jar” /> Applet failed to run. Please install the
Java plug-in. </object>
The type attribute specifies the Multipurpose Internet Mail Extensions (MIME), so that the browser knows to use the Java plug-in. The code parameter specifies the applet class,
while the archive parameter contains the location of the JAR file. If the JVM isn’t installed or not configured correctly in the browser, the text in the <object> element is displayed in the Web page.
AWT-based applets extend the Applet class and override the paint() method. The paint() method receives a Graphics object from the JVM to draw text, shapes, and components in the applet.
The Graphics Context
One of the first aspects in GUI programming that you’ll need to get used to is how methods are used. Although you’ll con- tinue to write and invoke your own methods, more often than not, the JVM environment will call methods automatically for you. It’s your responsibility to implement or override certain methods to execute custom code in response.
The paint() method is a good example of how this works. Because Applet is a subclass of Component and Container, it inherits the paint() method. In AWT, any time a component or its container is resized or redisplayed in any way, the paint() method is invoked. Rather than being concerned about the complexity of painting graphics for each OS, the JVM pro- vides a concrete implementation of the abstract class Graphics to the paint() method. The Graphics object is also known as the Graphics context, because the JVM with native OS-specific code provides the concrete class. As a program- mer, you need write only code in the paint() method that tells the Graphics context what to do.
The Graphics class contains many different methods for creat- ing simple and complex shapes, and drawing lines and text. One-dimensional segments and shape outlines are created by using the drawXXX() methods, while filled shapes is created by the fillXXX() methods. The setColor() method indicates the Color object used for painting colors, while setFont() specifies the Font object used for painting text. The following methods are common when painting shapes and text:
■ drawString()—Paints text using the specified x/y coordi- nate as the top-left corner of the text block.
Lesson 4 171
Graded Project172
■ drawLine()—Paints a line from one x/y coordinate to another.
■ drawArc() and fillArc()—Paints a line or filled area from an x/y coordinate within a rectangular block at specified start and end angles.
■ drawRect(), fillRect(), draw3DRect(), and fill3DRect()— Paints closed rectangle outline, fill with or without a 3-dimensional highlight starting at an x/y coordinate with a specified width and height.
■ drawOval() and fillOval()—Paints a closed circular shape within a rectangular block starting from a top-left x/y coordinate.
■ drawPolygon() and fillPolygon()—Paints a closed shape using an array of x/y coordinates or a Polygon object.
■ drawPolyline()—Paints an open shape using an array of x/y coordinates.
To designate where something is painted, you must specify the x/y coordinates of where it will appear in the component. The top-left corner is 0,0, while moving to the right increases the x value and moving down decreases the y value (Figure 10).
Take the following code:
Font font = new Font(“Arial”, Font.BOLD, 18 ); String text = “Have a nice day!”; g.setColor(Color.YELLOW); g.fillOval(100,100,200,200); g.setColor(Color.BLACK); g.fillOval(150, 150, 25, 25); g.fillOval(225, 150, 25, 25); g.drawArc(150, 180, 100, 75, -180, 180); //Measure text FontMetrics measure = g.getFontMetrics(font); int txtWidth = measure.stringWidth(text); g.setColor(Color.RED); g.setFont(font); g.drawString(text, 100 + 200/2 - txtWidth/2, 325);
This code will generate an applet that paints the graphic in Figure 11.
Graded Project 173
Applet Life Cycle
Before the paint() method is called, the init() and start() methods are invoked by the JVM. The init() method is invoked only once, while the start() method is invoked every time the applet is restarted. The stop() is invoked whenever the applet is suspended. The final method invoked is destroy(). This occurs only once when the applet is shut down. Unlike paint(), the init(), start(), stop(), and destroy() methods accept no arguments.
A common action to take in the init() method is to retrieve custom parameters from the Web page. The following HTML specifies a custom parameter for an applet:
Figure 10—x/y Coordinates Figure 11—Graphic Code Output
<object type=“application/x-java-applet” width=“800” height=“600”> <param name=“code” value=“AppletClass” /> <param name=“archive” value=“Applet.jar” />
<param name=“username” value=“jhester” /> Applet failed to run. Please install the Java plug-in.
</object>
Graded Project174
The following code retrieves the custom parameter username:
String username = getParameter(“username”);
Code in the init() method could also start other user threads, so that the code in destroy() would terminate those threads. Think of the start() and stop() methods as the methods that are invoked when an applet is paused and then resumed. Rather than consume resources indefinitely, use the stop() method to stop painting and calculations, until the start() method is invoked.
To change what’s displayed in the applet after fields have been updated to new values, you should invoke the repaint() method. This is because iteration within the paint() method would make the applet unresponsive to user events. The JVM will then invoke the paint() method again with the updated values. An overloaded version of repaint() accepts a bounding rectangle with x/y coordinates and width and height, so that only a portion of the applet is repainted.
Of course, applets can do more than simply paint graphics. They can play audio clips, display images, and even resize themselves. Table 14-1 on pages 488–489 in the textbook lists all of the methods provided by the Applet class. Because an Applet is a direct subclass of Panel, it inherits methods from the AWT classes Panel, Container, and Component as well.
Activity 17: Create a Basic Java Applet
1. Create a new Java Application project named Lesson5Activity17 in NetBeans.
2. Replace the Lesson5Activity17.java with the following code:
3. Run the file by right-clicking on the Lesson5Activity17.java file in Projects and choosing the Run File option in the contextual menu or using the SHIFT+F6 keyboard shortcut. This technique will auto- matically compile and run the class in the default appletviewer.
4. The applet should display a target with concentric black and red circles.
Event Delegation Model Applets, like any application with a GUI, are event driven. This means that rather than pushing the user through a predefined algorithm and prompting for input whenever it’s needed, a GUI application is primarily concerned with responding to user interactions whenever they occur. Such user interac- tions occur when a user clicks on a button, clicks and drags across the screen, or touches a tablet screen. These user interactions are called events.
import java.awt.*; import java.applet.*; public class Lesson5Activity17 extends Applet { public void init() { System.out.println(“Applet initialized!”); } public void start() { System.out.println(“Applet started!”); } public void stop() { System.out.println(“Applet stopped!”); } public void destroy() { System.out.println(“Applet destroyed!”); } public void paint (Graphics g) { for (int circles = 0; circles < 6; circles ++) {
g.setColor((circles % 2 == 0)? Color.BLACK : Color.RED); int size = 30 * circles; int align = size /2; g.fillOval(0 + align, 0 + align, 180 - size, 180 - size);
} } }
Graded Project 175
Programming in Java176
Events are divided by source and type. If a user clicks on a button, then that button will generate an ActionEvent. If a user changes the value in a textbox, then that textbox will generate a TextEvent. Hardware devices like keyboards and mice also generate events. Table 14-2 on page 491 in the textbook lists commonly used event classes.
Event Listening and Registration
To respond to an event, you need to use an event listener. An event listener is registered with one or more sources and is notified when that event occurs. Event listeners are interfaces in Java, so you must implement an interface to receive and respond to event notifications. The listener interface contains one or more methods that are invoked with the event type. Table 14-3 on page 492 in the textbook lists commonly used listener interfaces.
The following code implements the MouseListener and MouseMotionListener interfaces for a simple line drawing application:
public class MouseHandler implements MouseListener, MouseMotionListener {
int prevX, prevY, curX, curY; public void mouseClicked(MouseEvent me) {/*do nothing */} public void mouseMoved(MouseEvent me) {/*do nothing*/} public void mouseEntered(MouseEvent me) {
System.out.println(“Listening for mouse events!”); } public void mouseExited(MouseEvent me) {
System.out.println(“Ignoring mouse events!”); } public void mousePressed(MouseEvent me) {
prevX = me.getX(); prevY = me.getY(); } public void mouseDragged(MouseEvent me) {
curX = me.getX(); curY = me.getY(); } public void mouseReleased(MouseEvent me) {
//draw line from prevX,prevY to curX,curY }
}
Lesson 5 177
Most listener interfaces are restricted to one or two methods, but not so for low-level events involving keyboards, mice, focus, and windows. Unfortunately, you’ll notice that implementing an interface is all or nothing. You can’t implement a few methods of an interface—you must implement all methods, even if your application doesn’t need to listen for those events. Java provides listener adapter classes as a workaround for this issue. For example, instead of implementing the MouseListener, MouseMotionListener, and MouseWheelListener interfaces, you could simply subclass MouseAdapter. Java provides adapter classes that combine many related listener interfaces. These adapter classes include MouseAdapter, MouseMotionAdapter, FocusAdapter, KeyAdapter, and WindowAdapter.
The previous class could be briefer using the MouseAdapter class:
public class MouseHandler extends MouseAdapter { int prevX, prevY, curX, curY; public void mousePressed(MouseEvent me) {
prevX = me.getX(); prevY = me.getY(); } public void mouseDragged(MouseEvent me) {
curX = me.getX(); curY = me.getY(); } public void mouseReleased(MouseEvent me) {
//draw line }
}
To ensure that the listener is notified when an event occurs, you must register that listener with the event source. Java provides addXXXListener() and removeXXXListener() meth- ods to allow components to provide or withhold notifications, respectively.
Programming in Java178
The following code will instantiate the MouseHandler class to handle events associated with the MouseListener and MouseMotionListener interfaces:
MouseHandler mouseHandler = new MouseHandler(); addMouseListener(mouseHandler); addMouseMotionListener(mouseHandler);
It’s common to register listeners within the start() method of an applet and then remove those listeners in the stop() method. By doing this, you’re reducing the resource consumption while the user isn’t actively using the applet.
The following code removes notification of mouse-related events:
removeMouseListener(mouseHandler); removeMouseMotionListener(mouseHandler);
Anonymous Inner Classes
Often, listener classes are declared as inner classes within their components. This is because listener classes usually require access to the same Graphics context as the component and may need to share important fields and methods within the class. This is the preferred technique in most cases.
The following code declares the MouseHandler class within an applet class:
public class DrawApplet extends Applet { MouseHandler mh; public void init() {
mh = new MouseHandler(); } public void start() {
addMouseListener(mh); addMouseMotionListener(mh);
} public void paint(Graphics g) {
g.drawLine(mh.prevX, mh.prevY, mh.curX, mh.curY); } public void stop() {
removeMouseListener(mh); removeMouseMotionListener(mh);
}
Lesson 5 179
Because the listener object is referenced multiple times in the init(), start(), paint(), stop(), and destroy() methods, this code makes sense as a formally named class. But what if you wanted to declare a listener class, but used it only once and never needed to reference the class again?
Welcome to anonymous inner classes. An anonymous inner class is one that’s defined when it’s instantiated or “on-the-fly.” As you might guess, because the class is anonymous, you can’t refer to the class again and can access its methods only through the object. Thus, anonymous classes can contain only instance members. The following code defines an anonymous inner class for a listener to keyboard events:
addKeyListener( new KeyAdapter() {
public void keyTyped(KeyEvent ke) { if(ke.getKeyChar() == ‘s’) {
saveToFile(); }
} }
);
public void destroy () { mh = null; //dereferenced
} //inner listener class class MouseHandler extends MouseAdapter {
int prevX, prevY, curX, curY; public void mousePressed(MouseEvent me)
{ prevX = me.getX(); prevY = me.getY();
} public void mouseDragged(MouseEvent me)
{ curX = me.getX(); curY = me.getY();
} public void mouseReleased(MouseEvent me) {
repaint(); //in the Applet class }
} }
Programming in Java180
The class has no name, so you need only specify an interface or superclass name. An anonymous inner class can’t imple- ment more than one interface or extend a superclass and implement an interface. You must choose only one way of inheriting interface or implementation.
As you’ll notice, the convenience of anonymous inner classes is overwhelmed by the increased complexity it introduces into your code. Anonymous inner classes are often used for event handling, so you should be aware of them even if you choose not to use them often in your applications.
Activity 18: Create an Interactive Applet
1. Open the Lesson5Activity18 project in NetBeans.
2. In the Lesson5Activity18.java file, add the following import statement:
import java.awt.event.*;
3. In the Lesson5Activity18.java file, add the members to the Lesson5Activity18 class:
private StringBuilder input = new StringBuilder(); private KeyHandler kh = new KeyHandler(); private class KeyHandler extends KeyAdapter { public void keyTyped (KeyEvent ke) { input.append(ke.getKeyChar()); repaint(); }
This listener class will allow you to type text in the applet.
4. In the start() and stop() methods, make the following modifications:
public void start() { System.out.println(“Applet started!”);
this.addKeyListener(kh);
}
public void stop() { System.out.println(“Applet stopped!”);
Lesson 5 181
this.removeKeyListener(kh);
}
5. Add the following code to the paint() method:
g.setFont(new Font(“Arial”, Font.PLAIN, 14)); g.setColor(Color.GREEN); g.drawString(input.toString(), 50, 50);
6. Run the file in the appletviewer by right-clicking on the Lesson5Activity18.java file in Projects and choosing the Run File option in the contextual menu or using the SHIFT+F6 keyboard shortcut.
7. When you type keys on the keyboard, you should see them written to the applet.
Programming in Java182
Self-Check 14
1. What is an applet? How does it differ from a traditional stand-alone application?
__________________________________________________________
__________________________________________________________
2. Which method should you override to create the visual elements of an AWT-based applet?
__________________________________________________________
3. Which Graphics method should you use to paint the outline of a circle? Which Graphics method should use to paint an open shape?
__________________________________________________________
__________________________________________________________
4. What is the role of the source and listener in the event delegation model?
__________________________________________________________
5. What is an anonymous inner class?
__________________________________________________________
Check your answers with those on page 206
Lesson 5 183
ASSIGNMENT 15: USE SWING Read Assignment 15 in this study guide. Then read Chapter 15 in your textbook.
Assignment 15 continues GUI development by introducing Swing. This assignment also mentions the current evolution of GUI development with JavaFX. Be sure to complete the Try This activities in Chapter 15.
AWT and Swing
The difference between the abstract windowing toolkit (AWT) and Swing is stark. With AWT, the focus was on having GUI applications rely heavily on native code, so that an application developed in Java would look and feel similar to non-Java applications developed for that platform. With Swing, compo- nents have a unique look and feel that’s consistent across Java applications and platforms. In AWT, two components represented every visual element: a native implementation and a Java abstract class. In Swing, all visual elements are pure Java. For this reason, AWT components are known as heavyweight, while Swing components are considered light- weight. Although Swing still uses AWT for much of its plumbing, specifically events and graphics, its components are much more robust and customizable than those directly provided by AWT.
Swing is highly customizable, because its components implement a modified model-view-controller (MVC) pattern. In MVC, implementation is separated into three different elements: a model that represents the underlying object state, a view that displays that state, and a controller which modifies that state. The view is responsible for output only, while the controller accepts the input. The model is invoked by the view to be read and invoked by the controller to be modified. This means that a single object could have different views and be modified by more than one type of input. In Swing, the model and view are combined into a single thing known as the UI delegate.
Programming in Java184
In other words, a button doesn’t have to resemble a standard rectangle or behave in the same way as every other button. A button could be circular, transparent, or accept input via a mouse drag rather than a mouse click. In Swing, the only limitations are your imagination and the expectations of your users!
Containers and Layout Managers
Swing takes advantage of the concept of containership. Components aren’t lone elements, but placed within other elements, similar to placing smaller boxes within larger boxes. Top-level containers are at the top of the hierarchy and can’t be placed into other containers. The JWindow, JDialog, and JFrame containers are used for stand-alone applications, while the JApplet container is intended for Swing-based applets. The JFrame container is a standard application window, but JWindow and JDialog are intended for customized windows and dialogs that don’t contain standard interface elements.
Each top-level container defines a set of dividers known as panes. The top pane in the hierarchy is the JRootPane. You can manually divide the interface further by using the JPanel class. A layout manager controls how components and sub- panes are arranged in a pane. To specify a layout manager, you use the setLayout() method. You can choose from many different layout manager classes.
The simplest layout manager is FlowLayout (Figure 12). Components are laid out from left to right or right to left and top to bottom, based upon the available size in the container. Components can be aligned horizontally by center, left or right. A pixel amount can be specified for the horizontal and vertical gap between components. This is the default layout manager for JPanel objects.
Figure 12—FlowLayout Example
Lesson 5 185
The next layout manager is GridLayout (Figure 13). Components are laid out by row and column, where each component expands to fit its destination cell. Like FlowLayout, you can also specify a horizontal and vertical gap between cells.
Another simple layout manager is BorderLayout (Figure 14). With this layout manager, the panel is divided into five different regions: PAGE_START, PAGE_END, LINE_START, LINE_END, and CENTER. Components inserted into the PAGE_START and PAGE_END regions will have the preferred height, but expand to fit the width of the panel. Components inserted into the LINE_START and LINE_END regions will have the preferred width, but expand to fit the height of the panel. Components in the CENTER region will expand to fill any empty regions. You can also specify a horizontal and ver- tical gap between cells.
A more complex layout manager is GridBagLayout (Figure 15). Like GridLayout, the panel is divided into rows and columns. Unlike GridLayout, rows and columns can be different sizes and cells can span more than a single row or column. Also, you can ensure components use preferred widths and heights by specifying sizing constraints.
Figure 13—GridLayout Example
Figure 14— BorderLayout Example
Figure 15—GridBagLayout
Programming in Java186
BoxLayout (Figure 16) is a more flexi- ble version of FlowLayout. Like FlowLayout, controls are either stacked vertically or lined up horizon- tally. The Box class provides custom fillers known as struts to provide hori- zontal gaps between components and glue to create automatic space that grows vertically or horizontally. Rigid areas are fixed elements that can fill space both vertically and horizontally.
CardLayout is a layout manager that allows you to stack groups of components on top of each other. Because CardLayout only allows switching between groups using a combo box, the JTabbedPane component is the preferred technique for organizing groups of controls. To use the JTabbedPane component, you add components to a JPanel and then add that JPanel as a tab (Figure 17).
The other layout managers like GroupLayout and SpringLayout are intended for IDEs with visual designers. If you add a Swing GUI Form such as JDialog, JFrame, JPanel, or JApplet to a NetBeans project, then you can use either of these layout managers to click and drag components from a toolbox onto a visual designer (Figure 18). You can also place components using absolute positioning as well.
Figure 16—BoxLayout Example
Figure 17—JTabbedPane Example
Lesson 5 187
Swing Components
All Swing components are derived from the JComponent class, including JFrame. The table on page 507 of the text- book lists common Swing components, some of which are containers themselves. To add a component to a container, you need only invoke its add() method; to remove it, you use the remove() method. If using a layout manager that requires additional information on where to place the component, such as BorderLayout and GridLayout, you should specify those arguments as well.
The following code adds a button to a JFrame using BorderLayout:
frame.add( new JButton(“Button 1”), BorderLayout.PAGE_START);
Figure 18—NetBeans Visual Designer
Note: You’re not expected to use the NetBeans visual designer for proj- ects or activities. If you’re familiar with GUI-based interface design, then you’re wel- come to use the visual designers in NetBeans to reduce the amount of code you type.
Programming in Java188
As for JFrame properties, its constructor can accept a String for its window title and GraphicsConfiguration for the device screen. The setSize() method will set the width and height of the window in pixels, while the setVisible() method is required to display the window. By default, closing a JFrame won’t stop the application from running. To change this behavior, invoke the setDefaultCloseOperation() method with the EXIT_ON_CLOSE constant.
Event handlers in Swing use a special thread known as the event dispatcher. To launch a JFrame object from the main() method so that it uses the event dispatcher thread, rather than the main thread, you should use the invokeLater() or invokeAndWait() methods from the SwingUtilities class. The invokeLater() method is intended for the initial load in standalone applications, while the invokeAndWait() is used for UI updates when outside the event dispatcher thread and is intended for applets.
The following code uses an anonymous inner class that implements Runnable to instantiate JFrame:
SwingUtilities.invokeLater( new Runnable () { public void run() { new CustomJFrame(); }
});
Read through pages 515–530 in your textbook for an intro- duction to the JButton, JTextField, JCheckBox, and JList components. Other common Swing components you’ll probably use include JTextArea, JComboBox, JMenuBar, JSpinner, and JSlider. You can visit the Java tutorials on Oracle’s web- site for usage details on other important Swing components: http://tinyurl.com/cu69r87
Notice that Swing components use the same event delegation model you learned for AWT-based applets.
Activity 19: Create a Line Drawing Application with Swing
1. Create a new Java Application project named Lesson5Activity19 in NetBeans.
2. Replace the contents of Lesson5Activity19.java with the following code:
Lesson 5 189
import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*;
public class Lesson5Activity19 extends JFrame { ArrayList<Point> drawPoints = new ArrayList<>(); Color penColor = Color.BLACK; private Lesson5Activity19() { //initialize PaintComponent comPaint = new PaintComponent(); comPaint.setBackground(Color.WHITE); comPaint.setSize(300, 300); JPanel panButton = new JPanel(); panButton.setLayout(new GridLayout(4,0)); //create buttons JButton btnBlack = new JButton(“Black”); btnBlack.setForeground(Color.WHITE); btnBlack.setBackground(Color.BLACK); panButton.add(btnBlack); JButton btnRed = new JButton(“Red”); btnRed.setForeground(Color.BLACK); btnRed.setBackground(Color.RED); panButton.add(btnRed); JButton btnGreen = new JButton(“Green”); btnGreen.setForeground(Color.BLACK); btnGreen.setBackground(Color.GREEN); panButton.add(btnGreen); JButton btnBlue = new JButton(“Blue”); btnBlue.setForeground(Color.BLACK); btnBlue.setBackground(Color.BLUE); panButton.add(btnBlue); //add listeners MouseHandler mh = new MouseHandler(); comPaint.addMouseListener(mh); ActionHandler ah = new ActionHandler(); btnBlack.addActionListener(ah); btnRed.addActionListener(ah); btnGreen.addActionListener(ah); btnBlue.addActionListener(ah); this.setLayout(new BorderLayout()); this.add(comPaint, BorderLayout.CENTER);
Programming in Java190
this.add(panButton, BorderLayout.LINE_END); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setTitle(“Lines with Swing”); this.setSize(350, 300); this.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater( new Runnable () {
public void run() { new Lesson5Activity19(); } }); } //inner classes private class PaintComponent extends JComponent { public void paint(Graphics g) {
g.setColor(penColor); for (int i = 1; i < drawPoints.size(); i ++) {
g.drawLine(drawPoints.get(i-1).x, drawPoints.get(i-1).y, drawPoints.get(i).x, drawPoints.get(i).y);
} } } private class MouseHandler extends MouseAdapter { public void mousePressed(MouseEvent me) {
drawPoints.add(new Point(me.getX(), me.getY())); } public void mouseReleased(MouseEvent me) {
drawPoints.add(new Point(me.getX(), me.getY())); repaint();
} } private class ActionHandler implements ActionListener { public void actionPerformed(ActionEvent ae) {
JButton button = (JButton) ae.getSource(); penColor = button.getBackground(); //Set to button back-
ground color } } }
Lesson 5 191
Look carefully at this code. It uses a two-panel layout to display a custom component for drawing and a panel for color buttons. When you click on two different places in the drawing panel, a line is drawn between the two points, connecting any previous points as well. The buttons change the color of these lines.
3. Build and run the project. Once you get the hang of it, try customizing the application to draw other shapes.
Applets with Swing
How different is it to create a Swing-based applet than an AWT-based applet? Only two main differences exist. First, the Swing-based applet must be a subclass of JApplet, rather than Applet. Second, the UI is built on the event dis- patcher thread by invoking the SwingUtilities.invokeAndWait() method. Because JApplet is a subclass of Applet, the lifetime methods init(), start(), stop(), and destroy() are the same.
The example code on pages 537–538 demonstrates a Swing- based applet. It should look very recognizable to you, combining what you learned about applets and Swing in one place.
JavaFX
Although Swing-based applications are still very common, the next generation of Java GUI applications is using JavaFX (Figure 19). JavaFX provides rich graphics and robust anima- tion support for applications that are designed to run across traditional desktop, mobile, and embedded platforms. The API for JavaFX is very similar to Swing in many respects, but it provides a greater range of visual customization and multi- media support. All UI classes and interfaces for JavaFX are located in the javafx package, and no implementation is reused from AWT or Swing.
Programming in Java192
JavaFX applications extend the Application class and use their start() method as the main entry point. Content is stored on a stage, divided by scenes and further by frames. JavaFX also supports standard Web technologies such as HTML and CSS (Cascading Style Sheets) for content and styling.
Although a more thorough discussion on JavaFX is outside this course, the NetBeans IDE contains a few samples for JavaFX applications that you can run and modify to become more familiar. You can also visit the JavaFX documentation provided by the Oracle website at http://docs.oracle.com/ javafx/index.html for detailed tutorials and step-by-step exercises.
Figure 19—Colorful Circles Sample Project for JavaFX
Lesson 5 193
Self-Check 15
1. How does Swing differ from AWT?
__________________________________________________________
2. What is the MVC pattern and how does Swing modify it?
__________________________________________________________
3. Which layout manager is optimal for a table-like layout that allows components to expand more than one column or row?
__________________________________________________________
4. Which method must you use to instantiate a JFrame object? Which method must you invoke on a JFrame object for it to display?
__________________________________________________________
__________________________________________________________
5. How does JavaFX differ from Swing?
__________________________________________________________
Check your answers with those on page 207.
Programming in Java194
NOTES
Graphical User Interface
OVERVIEW
Now you’ll develop a graphical user interface for the TicTacToe game. This project will assess your understanding of AWT, Swing, and event handling.
Make sure that you follow all directions completely and verify your results before submitting the project. Remember to include all required components in your solution.
YOUR PROJECT
In this project, you’ll create the GUI front-end for the TicTacToe game. This application will leverage the classes you wrote in the graded project for Lesson 3. You’ll copy code from Graded Project 3 for this project.
Figure 20 is a guide for the completed user interface.
195
G ra
d e
d P
ro je
c t
G ra
d e
d P
ro je
c t
FIGURE 20—The Completed Tic Tac Toe Game
Graded Project196
INSTRUCTIONS
1. In NetBeans, create a new Java Application project named TicTacToeGUIGame.
2. Copy the games.board package from the Lesson 3 proj- ect named BoardGameTester.
■ Right-click on the game.board package in the BoardGameTester project of the Projects pane panel.
■ Choose the Copy option from the context menu or use the keyboard shortcut CTRL+C.
■ Paste it in the TicTacToeGUIGame project using the Paste option in the context menu or the keyboard shortcut CTRL+V.
Make sure to copy and paste the package in the Source Packages folder.
3. In the Cell.java file, have the Cell class extend the JButton class. This action will ensure that each cell on the board has the look and feel of a standard Java button.
4. Override the paintComponent method in the Cell class as follows:
public void paintComponent(Graphics g) {
//paint the basic button first
super.paintComponent(g);
int offset = 5;
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(5));
switch(content) {
case NOUGHT:
g2.setColor(Color.RED);
//Draw O
g2.drawOval(offset, offset, this.getWidth() - offset * 2, this.getHeight() - offset * 2);
break;
case CROSS:
g2.setColor(Color.BLACK);
//Draw X
Graded Project 197
Note: This code uses the enhanced Graphics2D class to set the stroke thickness to more than one pixel. The Oracle documentation provides more guidance on creat- ing complex geometric shapes using the Graphics2D class at http://docs.oracle.com/javase/tutorial/2d/ geometry/index.html. Remember to import the java.awt and javax.swing packages!
5. In the Board.java file, have the Board class extend the JPanel class. This action will ensure that the board can lay out each cell and process its UI events.
6. Make the following modifications to the Board constructor:
These changes will add each cell to the UI and assign an ActionListener object to each cell.
Note: Remember to import the java.awt, java.awt.event, and javax.swing packages.
7. In the TicTacToeGUIGame.java file, have the TicTacToeGUIGame class extend JFrame. This action will ensure that the game is hosted in a Java window.
8. Import the games.board, java.awt, and javax.swing packages.
g2.drawLine(offset, offset, this.getWidth() - offset , this.getHeight() - offset );
g2.drawLine(this.getWidth() - offset, offset , offset, this.getHeight()- offset);
break;
}
}
public Board(int rows, int columns, ActionListener ah) { cells = new Cell[rows][columns]; this.setLayout(new GridLayout()); for( int r = 0; r < cells.length; r++ ) {
for (int c = 0; c < cells[r].length; c++) { cells[r][c] = new Cell(r,c); this.add(cells[r][c]); cells[r][c].addActionListener(ah);
} } }
Graded Project198
9. Add the following code to the main method:
SwingUtilities.invokeLater( new Runnable () { public void run() { new TicTacToeGUIGame(); } });
10. Declare the following instance variables in TicTacToeGUIGame:
private Board gb; private int turn;
11. Add the following method to handle each turn:
private void takeTurn(Cell c) { Mark curMark = (turn++ % 2 == 0)? Mark.NOUGHT : Mark.CROSS; gb.setCell(curMark, c.getRow(), c.getColumn()); }
12. Define the following constructor to create the board, provide the event listener, and display the board in the window:
private TicTacToeGUIGame() { gb = new Board(3, 3, new ActionListener() { public void actionPerformed(ActionEvent ae) { Cell c = (Cell) ae.getSource(); takeTurn(c); } }); this.add(gb); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setTitle(“TIC-TAC-TOE”); this.setSize(300, 300); this.setVisible(true); }
13. Compile and run the project. Test to make sure each button displays a nought or cross when clicked.
Graded Project 199
SUBMISSION GUIDELINES
To submit your project, you should submit the final JAR file:
TicTacToeGUIGame.jar
To ensure the JAR file is built, you should click the Build button or hit the F11 key.
To find the JAR file with NetBeans, go to the TicTacToeGUIGame project folder. To determine this folder, right-click on TicTacToeGUIGame project in the Projects panel. Copy the value for the Project Folder textbox using the keyboard shortcut CTRL+C. In Windows Explorer, paste the project folder path and hit the ENTER key. Copy the TicTacToeGUIGame.jar file from the dist folder to your desktop or any other temporary location.
Follow this procedure to submit your project online:
1. Log on to the Penn Foster website and go to My Courses.
2. Click Take Exam.
3. Attach your file as follows:
a. Click on the Browse box.
b. Locate the file you wish to attach.
c. Double-click on the file.
d. Click Upload File.
4. Enter your e-mail address in the box provided. (Note: This information is required for online submissions.)
5. If you wish to tell your instructor anything specific regarding this assignment, enter it in the Message box.
6. Click Submit File.
Graded Project200
Grading Criteria
Your instructor will use the following guidelines to grade your project.
Cell class is modified correctly 20 points
Board class is modified correctly 20 points
The game window displays correctly 20 points
The buttons behave correctly when clicked 20 points
JAR file is provided: 20 points
TOTAL 100 points
201
A n
s w
e r
s A
n s
w e
r s
Self-Check 1 1. Procedural programming languages use step-by-step
instructions, while object-oriented programming (OOP) languages model real-world structures and relationships. Procedural programming languages separate data and instructions, but object-oriented languages combine them into fields and methods of objects.
2. A Java application that’s written and compiled can run on any platform with the Java Virtual Machine (JVM) installed. The developer doesn’t need to write code for a specific CPU, motherboard, chipset, or operating system.
Self-Check 2 1. Java Micro Edition (ME) is a configurable subset of Java
SE (Standard Edition), because it must support smaller, embedded devices that can’t store all class libraries found in SE.
2. The JDK (Java Development Kit) is required to write applications, because it includes the compiler and other developer tools. The JDK isn’t required to run Java applications—only the JRE (Java Runtime Environment) is needed. The JRE includes the JVM (Java Virtual Machine), runtime commands and applications, and essential class libraries.
Self-Check 3 1. The extension of a source code file is .java and the
command that compiles it is javac.
2. The extension of a bytecode file is .class and the com- mand that runs it is java or javaw.
Self-Check 4 1. Primitive data types are built-in data types that are fixed
in size and stored only in the default memory stack.
2. Integers are whole numbers, while floating-point numbers support fractional values. Floating-point numbers use scale and precision to represent values, while integers only reserve a dedicated sign bit.
3. You should use explicit casting for a data type when moving values from a larger container into a smaller one. The conversion could result in a loss of precision, so you must use explicit casting.
4. The value of the result is 7.0. According to operator prece- dence, the parenthetical subtraction will occur first (5 – 10) to yield –5. Then, the modulus operator will be used (15 % 7) to yield a remainder of 1. Next, the multi- plication operation will be performed (1 * 10) to yield 10. Remember the ^ operator is used for bitwise XOR opera- tions, so it will be performed last. The addition operation occurs next (–5 + 10) and yields 5. Finally, the XOR operation compares 5 (0b101) to 2 (0b010) and yields 7 (0b111). The final result will be 7.0 because the result variable is a double. For more on bitwise and shift oper- ators, read pages 166–171 in Chapter 5 of the textbook.
5. The value of charVal is R. The toUpperCase() method returns the String value as STRINGS OF JAVA. The charAt() method with the 2 argument will return the third character R.
Self-Check 5 1. The do-while statement executes at least once, because
the while expression isn’t evaluated until after the first iteration.
2. The for statement uses an explicit counter to loop.
3. The break and continue statements. The break state- ment exits out of an iterative loop, while the continue statement skips to the next iteration.
Self-Check Answers202
Self-Check Answers 203
4. A method can return only one value. A method may not return a value if its return type is void.
5. No arguments are required for a varargs parameter. Zero or more arguments can be specified for a varargs parameter.
Self-Check 6 1. In Java, elements in an array must be the same data
type, the length of an array must be an int, and its length is fixed and can’t be modified.
2. The length field returns the number of elements in the array.
3. The index value 0 will return the first element in the array, because arrays use zero-based indexing.
Self-Check 7 1. An exception is simply an abnormal condition that
occurs in a program. Some exceptions are errors from which an application can’t recover, while others can be handled by users or programmers to continue running the application.
2. The try/catch blocks handle exceptions. The try block contains code that might throw an exception, while the catch block performs an action when the exception is actually thrown.
3. The throws keyword is used in method declarations to indicate that invoking the method will require dealing with a specific exception, while the throw keyword is used to manually throw an exception within a method.
Self-Check Answers204
Self-Check 8 1. Object references are stored in the memory heap and are
actually pointers to that object’s data, whereas primitive types are stored on the memory stack and only contain a value.
2. Encapsulation is designing an object so that its state (fields) is protected from direct access and all interac- tions with the object involve its behaviors (methods).
3. Instance members are unique to each object, whereas class members affect all objects of a class.
4. A class is instantiated when the new keyword is used and memory in the heap is reserved. An object is final- ized when the garbage collector prepares to delete the object from memory and invokes the finalize() method.
Self-Check 9 1. Inheritance is when one or more classes inherit code
from another class. The superclass contains the inher- ited code, while its subclasses are those that receive the inherited code.
2. The output is Sub print() because the print() method is overridden in Subclass. Polymorphism dictates that the actual method invoked depends on the type of the object, not the reference type of its variable. Although the variable obj is of type SuperClass, the actual object is of type SubClass.
3. Abstract classes are those that can’t be instantiated but can contain methods without definition code. Concrete classes are subclasses that provide the definition for abstract methods.
4. In Java, a package prevents naming conflicts between classes and other types and provides an organized hier- archy for data types.
Self-Check 10 1. The phrase “inheritance without the side effects” describes
how using interfaces ensures only the method declarations, not the implementation details of each method, are inherited by each class. Also, in class inheritance, there’s tight coupling and only a single class can be inherited. In interface implementation, there’s loose coupling and multiple interfaces that can be implemented by a single class.
2. Abstract classes can contain implementation and only support single inheritance. Interfaces can’t contain implementation, but support multiple inheritance.
3. An enumeration is a custom data type that contains a limited set of named values.
Self-Check 11 1. Type wrappers are special classes that represent primi-
tive values, so that they can be stored, used, and passed as objects.
2. Autoboxing is the automatic boxing of primitive types into objects and unboxing of objects into primitive types. This is provided by the runtime without requiring manual boxing or unboxing with type wrapper methods.
3. Only those object types that implement the generic Comparable interface are allowed for both the array and elem parameters.
Self-Check 12 1. A byte stream reads/writes un-encoded data bytes, while
a character stream code/encodes that data. Buffered streams wrap character streams so that characters can read/write line by line, rather than character by character.
2. The read() method is standard for input streams which retrieve data from a stream. The write() method is stan- dard for output streams which modify data in a stream.
Self-Check Answers 205
3. System.in is the standard method for retrieving data using the keyboard. System.out and System.err are used to generate output for all-purpose and error text, respec- tively.
4. Resource objects are automatically closed and derefer- enced at the end of a try-with-resources block. If the close() method throws an exception, then any other exceptions thrown in the try-with-resources block will be suppressed.
5. The Path interface represents the location of a file or directory in the java.nio package.
Self-Check 13 1. A thread is a task performed by an application and can
be controlled by the programmer. A process is a unique runtime environment for a running application that is controlled by the OS.
2. You can either implement the Runnable interface directly or extend the Thread class, which also imple- ments the Runnable interface.
3. The Runnable interface provides a run() method that can’t return a value, while the Callable interface provides a call() method that can return a value.
4. The initial state is runnable after the start() method is invoked for a thread.
5. The synchronized keyword allows access to a code block or method by only one thread at a time.
Self-Check 14 1. An applet is a small GUI application embedded in a Web
page. Unlike stand-alone applications, applets can’t run outside the browser and are placed in a security sandbox.
2. The paint() method should be overridden to create visual elements for an AWT-based applet. The repaint() method is invoked to update those visual elements.
Self-Check Answers206
3. The drawOval() method is used to paint the outline of a circle, while the drawPolyline() is used to paint an open shape.
4. The event source is the visual component or input device on which an action occurs. The event listener is an object that’s notified by the source when a type of action occurs by receiving an event object.
5. An anonymous inner class is one that’s defined “on-the-fly” without a name. The class definition is provided when an object is instantiated, so that the class can’t be referenced outside the object.
Self-Check 15 1. AWT relies heavily on native code for the visual elements,
while Swing uses pure Java components. Swing still uses AWT for events and graphics, however.
2. In MVC, a model represents the underlying object state, while the controller and view provide the input and out- put for that state, respectively. Swing modifies the MVC pattern by combining the controller and view into the UI delegate.
3. The optimal layout manager would be GridBagLayout. Cells can span more than a single row or column in this layout manager.
4. To instantiate a JFrame object on the event dispatcher thread, you should use the invokeLater() method. To display the JFrame object, you should invoke the setVisible() method, specifying true.
5. JavaFX provides a greater range of visual customization and multimedia support and doesn’t rely on AWT imple- mentations.
Self-Check Answers 207