34
Advanced OOP J2SE Professional Skills Development 10-1 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited. Advanced OOP Objectives Learn how to use final methods and classes. Understand the purpose of abstract classes. Discover the benefits of using interfaces. Learn how to use inner classes. See how to create an anonymous inner class. Explore the various methods of cloning objects. Learn how and when to use the equals() and hashCode() methods.

Ch10 - Advanced OOP · In Java, you can also use the final keyword in method declarations and class declarations. final Methods When you declare a method as final, the Java compiler

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

Advanced OOP

J2SE Professional Skills Development 10-1 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Advanced OOP

Objectives

• Learn how to use final methods and classes.

• Understand the purpose of abstract classes.

• Discover the benefits of using interfaces.

• Learn how to use inner classes.

• See how to create an anonymous inner class.

• Explore the various methods of cloning objects.

• Learn how and when to use the equals() and hashCode() methods.

Advanced OOP

10-2 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

final Revisited You have already seen how to use the final keyword when declaring constants. In Java, you can also use the final keyword in method declarations and class declarations.

final Methods

When you declare a method as final, the Java compiler prevents the method from being overridden in any subclasses that inherit it. If you want to ensure that the specific implementation of a method is immutable in all subclasses, you should declare it final.

The one situation where you may not declare a method as final is in the case of abstract methods. Any subclasses that inherit an abstract method must be able to override it. Therefore you cannot declare abstract methods as final. You will learn about abstract classes in detail in the next major section of this chapter.

final Classes

You may also declare classes with the final keyword. The Java compiler will prevent anyone from creating a subclass that extends the final class. The java.lang package has several final classes, including the Double class, which has the following declaration:

public final class Double extends Number

Abstract Classes

J2SE Professional Skills Development 10-3 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Abstract Classes An abstract class represents an abstract concept and can only be subclassed. The intent is to provide a common interface to all classes that extend from it. You create an abstract class when you want to manipulate a set of classes through a common interface. It is meant to express only an interface, and not a particular implementation.

Abstract Methods An abstract method has a declaration, but it has no method body. It serves as a name reservation and forces all subclasses to implement a method with the identical name, parameter list, and return type.

The Java compiler considers any class that contains one or more abstract methods to be an abstract class, and requires you to declare it as such using the abstract keyword. Abstract classes contain at least a single abstract method.

An abstract class can also have concrete methods, which are methods that have an implementation in the method body. In fact, most abstract classes have a mix of both abstract and concrete methods.

When you extend an abstract class, you must implement all of its abstract methods. The one exception to this is if you also declare the subclass as abstract, you force the next subclass to implement any remaining abstract methods.

A good example of an abstract class in the java.lang package is the Number class. It contains several abstract methods as well as some concrete methods.

Advanced OOP

10-4 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

public abstract class Number

implements java.io.Serializable {

public abstract int intValue();

public abstract long longValue();

public abstract float floatValue();

public abstract double doubleValue();

public byte byteValue() {

return (byte)intValue();

}

public short shortValue() {

return (short)intValue();

}

private static final long

serialVersionUID = -8742448824652078965L;

}

Why Be Abstract?

There are two main reasons for creating an abstract method and therefore, an abstract class. One is to ensure consistency in method names for all subclasses. The other is because at some levels of abstraction, the method names may be appropriate but any implementation would be completely useless.

Polymorphic Advantages

The first reason deals with polymorphism. For example, consider the Number class mentioned in the previous code. There are several number subclasses such as Byte, Double, Integer, Short, Long, etc., and each of these should have the same conversion functionality. Declaring these methods in the Number class ensures that all subclasses will have methods by the same name. This makes development simpler and gives more power to the programmer.

Since several number subclasses will need to do similar activities, the Number class declares several abstract methods that apply to all subclasses.

Abstract Classes

J2SE Professional Skills Development 10-5 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Not Real Enough

During the design process for an application, when examining the entities or objects that your system needs, you are likely to discover actions that in name, apply to all members that will inherit from a superclass, but whose actual activity is totally generic. In this situation, you need to separate the name or initial declaration of a method and the body of that method.

For example, if you think about the animal kingdom, you know that all animals speak but that each makes its own unique sound. When we design for this scenario, the method name, eat(), should show up in the animal class even though there is no implementation appropriate for this class. Any body of code cannot be correctly associated with a class until you inherit from the animal class to create a specific critter.

Advanced OOP

10-6 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Interfaces An Interface is essentially the same as an abstract class that has absolutely no concrete methods. An Interface tends to have fewer methods than an abstract or concrete class. This is because interfaces frequently represent single concepts that are completely abstract at the level they are declared.

Java allows for single inheritance but not for multiple inheritance. However, in order to accomplish the same things that multiple inheritance allows you to do, the designers of Java decided to provide interfaces to let the programmer avoid the many complexities of multiple inheritance.

A very common interface contained in the java.lang package is the Comparable interface. Shown below, it contains a single method declaration. Interface methods are always public whether declared so or not. They are also always considered to be instance methods and therefore cannot be declared static.

public interface Comparable {

public int compareTo(Object o);

}

The Double class is one of many classes that implement the Comparable interface.

public final class Double extends Number

implements Comparable {

Even though Java only allows single inheritance, you can build a class that implements as many interfaces as you want. The Date class for example, implements three interfaces. It implements Serializable, Cloneable, and the Comparable interfaces.

public class Date implements java.io.Serializable,

Cloneable, Comparable {

Additionally, interfaces can contain constants along with their methods. You must also declare a constant public just as you would a method. However, all constants must be static. The SocketOptions interface declares many constants with only a couple of methods.

Interfaces

J2SE Professional Skills Development 10-7 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

public interface SocketOptions {

public void setOption(int optID, Object value)

throws SocketException;

public Object getOption(int optID)

throws SocketException;

public final static int TCP_NODELAY = 0x0001;

public final static int SO_BINDADDR = 0x000F;

public final static int SO_REUSEADDR = 0x04;

public final static int SO_BROADCAST = 0x0020;

public final static int IP_MULTICAST_IF = 0x10;

public final static int IP_MULTICAST_IF2 = 0x1f;

public final static int IP_MULTICAST_LOOP = 0x12;

public final static int IP_TOS = 0x3;

public final static int SO_LINGER = 0x0080;

public final static int SO_TIMEOUT = 0x1006;

public final static int SO_SNDBUF = 0x1001;

public final static int SO_RCVBUF = 0x1002;

public final static int SO_KEEPALIVE = 0x0008;

public final static int SO_OOBINLINE = 0x1003;

}

Advanced OOP

10-8 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Inner Classes In the Java language, it is possible to place class definitions inside other class definitions. This technique is referred to as using an inner class. The ability to do this allows you to group classes that logically belong together and control data access between classes. As a member of its outer class, an inner class has access to its outer class’ members, even if they are declared private.

In the following example, the main class Course represents a teaching course object. Within this class, there are two inner classes (Instructor and Students). These inner classes are member variables of the outer Course class. The outer class constructor creates and initializes the Instructor and Students variables. Get and Set methods have also been created to access the inner class variables.

When this program is run, a Course object is created. Using the constructor arguments, the three member variables are initialized. The system will then access the variables and print their values.

public class Course {

String title;

Instructor instructor;

Students students;

public static void main(String[] args) {

String course = "Java";

String instructor = "Neal";

String[] students = new String[] {"Tim", "Alan", _

"Jamie", "Noah"};

Course course = new Course(course, instructor, _

students);

System.out.println("Course: " + _

course.getTitle());

System.out.println("Instructor: " + _

course.getInstructor().getName());

System.out.print("Students: " + _

course.getStudents().getNames());

}

See Course.java in the \course directory

Inner Classes

J2SE Professional Skills Development 10-9 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Course(String t, String i, String[] s) {

this.title = t;

this.instructor = new Instructor(i);

this.students = new Students(s);

}

public String getTitle() {

return this.title;

}

// Getter for Instructor object

public Instructor getInstructor() {

return instructor;

}

// Getter for Students object

public Students getStudents() {

return students;

}

// Inner class

class Instructor {

private String name;

Instructor(String s) {

this.name = s;

}

public String getName() {

return name;

}

}

// Inner class

class Students {

private String[] names;

Students(String[] s) {

this.names = s;

Advanced OOP

10-10 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

}

// Returns String representation of array

public String getNames() {

String s = "";

for (int i = 0; i < names.length; i++) {

s = s + names[i];

if (i < (names.length - 1)) {

s = s + ", ";

}

}

return s;

}

}

}

The result is:

Course: Java

Instructor: Neal

Students: Tim, Alan, Jamie, Noah

Anonymous Classes

J2SE Professional Skills Development 10-11 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Anonymous Classes An anonymous inner class allows you to create a single, local object within an expression by wrapping it in a new method. These classes are typically used for adding functionality to a specific object (such as a button) and are usually simple and localized.

Anonymous inner classes are similar to local classes, but they have no class name. Instead, class declaration and instantiation are combined. They are most often used in combination with the event handling system. Assigning the event handling code directly to the event source eliminates the need to create additional subclasses from the event interfaces.

button.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

System.out.println("The button was pressed!");

}

});

In this example, an ActionListener object is created and passed in as a method argument to the button. The button will maintain a reference to this object and will be the only event source available to the listener.

Advanced OOP

10-12 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Cloning Cloning, which makes a copy of an object, starts with the Object class. This is because the Object class has a clone() method. It creates a new object that is a copy of the current object, regardless of the class to which the original object belongs. However, this can only happen if the class being cloned indicates that this process is acceptable. The class does this by implementing the Cloneable interface.

The Cloneable Interface

The Cloneable interface, which is rather unusual as interfaces go, declares no methods. You use it simply as a type indicator. This kind of interface is called a tagging interface, which is useful in a couple of different scenarios. The more common of the two is so that you may use instance of <interface> on an instance of this class and it will respond in the affirmative. The other situation, which Cloneable falls into, is essentially a declaration by the designer of the class that they understand and are aware of a particular process. In this case, it is the cloning process, which is inherited from the Object class. More specifically, implementing the Cloneable interface means that you know your class has a useable clone() method.

At first, it might appear that all classes fit into this category because as previously mentioned, the Object class has a clone() method and all classes descend from the Object class. However, upon closer inspection of the Object class’ clone() method’s declaration it reveals that it is declared protected and therefore not useable to descendent classes because it is not callable from outside any class. Therefore, for a class to become cloneable, it must override the clone() method declaring it public so that it becomes useable by methods outside of the class to be cloned. Implementing Cloneable (i.e., the clone() method) comes with the additional requirement to advertise throwing CloneNotSupportedException.

Shallow Copy

The Object class’s clone() method clones an object by creating a new object of the same type and then copying the value of each field to the new object. The term for this type of object copying is shallow copy.

A shallow copy for a Manager class might look something like this:

Cloning

J2SE Professional Skills Development 10-13 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

public Manager clone() {

Manager newMgr = new Manager();

newMgr.SSN = this.SSN;

newMgr.hireYear = this.hireYear;

newMgr.salary = this.salary;

newMgr.setName(this.name);

newMgr.setAge(this.age);

newMgr.setGreeting(this.greeting);

return newMgr;

}

While on the surface this may appear to be sufficient, looks in this case are certainly deceiving. As the name implies, you need to go a little deeper in the copying process.

Suppose that you have a manager that is so good that you want to clone your star employee. Updating the Manager class used earlier, you would first have the class implement the Cloneable interface, as well as a clone() method:

public class Manager extends Employee _

implements Cloneable {

String department;

Employee assistant;

public Manager(String name, int age, String greeting,

int SSN, int hireYear, double salary,

String department, Employee assistant) {

super(name, age, greeting, SSN, hireYear, salary);

this.department = department;

this.assistant = assistant;

}

public double calcBonus(int percent) {

// use superclass’ calcBonus() for the base %

double bonus = super.calcBonus(percent);

Calendar cal = GregorianCalendar.getInstance();

int currYear = cal.get(Calendar.YEAR);

// calculate the additional Manager bonus

See Manager.java in the \clone\ people\employee directory

Advanced OOP

10-14 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

double mgrBonus = (currYear - super.getHireYear())

* 1000;

return (bonus + mgrBonus); // return the sum

}

public String getDepartment() {

return department;

}

public void setDepartment(String department) {

this.department = department;

}

public Employee getAssistant() {

return assistant;

}

public void setAssistant(Employee assistant) {

this.assistant = assistant;

}

public Object clone()

throws CloneNotSupportedException {

return super.clone();

}

}

With the changes to the Manager class, you can now create a program called ManagerClone to take advantage of its new clone method:

See Manager Clone.java in the \clone directory

Cloning

J2SE Professional Skills Development 10-15 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

public class ManagerClone {

public static void main(String[] args){

Manager mgrTwo = null;

Employee oldEmp = new Employee("George", 35, _

"Howdy", 123456789, 2001, 40000);

Manager mgrOne = new Manager("John", 45, _

"Hello", 987654321, 1963, 100000, _

"Finance", oldEmp);

try {

mgrTwo = (Manager)mgrOne.clone();

mgrTwo.getAssistant().setName("Paul");

} catch (CloneNotSupportedException cns) {

}

System.out.println(mgrOne.getGreeting() + _

", my name is " + mgrOne.getName() + _

". My assistant is " + _

mgrOne.getAssistant().getName() + ".");

System.out.println(mgrTwo.getGreeting() + _

", my name is " + mgrTwo.getName() + _

". My assistant is " + _

mgrTwo.getAssistant().getName() + ".");

}

}

The resulting output from the previous code using the default clone() method is:

Howdy, my name is John. My assistant is George.

Howdy, my name is John. My assistant is George.

Advanced OOP

10-16 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

So now, you either have a copy of John or merely an echo. You will go with the former. Then, with the cloned object, change the Employee’s name and the Manager’s name. Afterwards, display the output of the new employee and their manager. To do this, insert the following code at the end of the ManagerClone class.

mgrTwo.setName("Paul");

mgrTwo.getAssistant().setName("Ringo");

System.out.println(mgrOne.getGreeting() + _

", my name is " + mgrOne.getName() + _

". My assistant is " + _

mgrOne.getAssistant().getName() + ".");

System.out.println(mgrTwo.getGreeting() + _

", my name is " + mgrTwo.getName() + _

". My assistant is " + _

mgrTwo.getAssistant().getName() + ".");

After changing the names of the employee and his manager, you have additional output.

Hello, my name is John. I work for George.

Hello, my name is John. I work for George.

Hello, my name is John. I work for Ringo.

Hello, my name is Paul. I work for Ringo.

The problem with the default clone() method is that when it encounters an object stored in a field, such as the Manager’s assistant, instead of copying each of its fields just as it was doing with the original object, it takes a shortcut and makes a copy of the reference to that object. As a result, the original object and its copy both have a field whose value is the same object instance.

Figure 1 illustrates how the default clone method handles object field values when copying objects.

Cloning

J2SE Professional Skills Development 10-17 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Figure 1. A shallow copy example.

Deep Copy The behavior illustrated in the previous example is not what is typically desired when you want a copy of an object. What you most likely prefer is a deep copy. In this case, you’ll need to alter the clone() method of the Manager class and implement the clone() method in the Employee class to return a new employee. You will also need to implement the Cloneable interface in the Person class.

Advanced OOP

10-18 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

public class Person implements Cloneable {

...

}

public class Employee extends Person {

...

public Object clone()

throws CloneNotSupportedException {

Employee emp = (Employee)super.clone();

return emp;

}

}

public class Manager extends Employee {

...

public Object clone()

throws CloneNotSupportedException {

Manager mgr = (Manager)super.clone();

mgr.assistant = (Employee)this.assistant.clone();

return mgr;

}

}

Cloning

J2SE Professional Skills Development 10-19 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

NOTE Even though you are overriding the clone() method in the subclasses Manager and Employee, it is no longer necessary to implement the interface in the class definition since Cloneable is now implemented in the super class Person.

Now when you run the program, you have two different manager objects with two different assistant objects. The results look like the following:

Hello, my name is John. I work for George.

Hello, my name is John. I work for George.

Hello, my name is John. I work for George.

Hello, my name is Paul. I work for Ringo.

Advanced OOP

10-20 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Important Methods: equals() and hashCode()

The Object class declares two other methods worth mentioning. They are the equals() and the hashCode() methods. These methods are similar to the clone() method in that they provide some default behavior, perhaps even useful behavior, but normally need to be overridden in order to be optimized. One significant difference is that they are not implicitly related to an interface. Another is that they are both declared public so that you can use them in their default state, not forcing you to override them.

The equals() Method

The equals() method is declared in the Object class and compares two objects to be the same. This is not to be confused with a comparison to determine if they are equal, meaning that all of their data members are the same The equals() method actually compares two objects to determine if they are the same object, not merely equal as the name implies.

As an example, let’s compare the two employees cloned in the preceding example in the Cloning section and show them to be not equal.

public class EmployeeClone {

public static void main(String[] args){

Employee newEmp = null;

Manager mgr = new Manager("John", 45, "Hello",

987654321, 1963, 100000, "Finance");

Employee oldEmp = new Employee("George", 35,

"Howdy", 123456789, 2001, 40000, mgr);

try {

newEmp = (Employee)oldEmp.clone();

} catch (CloneNotSupportedException cns) {

System.out.println("Employee not cloned: " +

"recheck the flux capacitor");

Important Methods: equals() and hashCode()

J2SE Professional Skills Development 10-21 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

} catch (Exception e) {

e.printStackTrace();

}

if (oldEmp.equals(newEmp)) {

System.out.println("Equal");

} else {

System.out.println("Not Equal");

}

}

}

The result is:

Not Equal

The hashCode() Method

The short definition for the hashCode() method is that it calculates a hash code value for a given object and returns this value as an int. It is doubtful that Webster would consider this to be a sufficient definition, much less a thorough explanation so let’s elaborate further by first regressing a bit.

Consider a scenario in which you must store many objects in a collection for later retrieval. One process for doing this involves pairing each object to be stored with a key object. This key must be unique for all occurrences of the collection of objects being stored, but the key itself may not be something that you can search upon easily, at least not for a large number of occurrences. Primitive ints, on the other hand, are a much more efficient value on which to conduct a search. What the hashCode() method does is take the key associated with an object and creates an int value known as a hash code for each object to be stored. This process is known as hashing. In an ideal world, the hashCode() method generates a unique hash code for every key but in the real world, this often does not occur.

The following code uses the hashCode() method to print the hash codes and test for equality of the Employee objects created in the previous example.

Advanced OOP

10-22 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

if (oldEmp.hashCode() == newEmp.hashCode()) {

System.out.println("Equal");

} else {

System.out.println("Not Equal");

}

System.out.println("oldEmp = " + oldEmp.hashCode());

System.out.println("newEmp = " + newEmp.hashCode());

The result will be similar to this:

Not Equal

oldEmp = 4152583

newEmp = 16032330

NOTE Hash code values are based on memory address so they will always be different.

Important Methods: equals() and hashCode()

J2SE Professional Skills Development 10-23 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Summary • Declaring a method as final, keeps subclasses from overriding them.

• Declaring a class as final prohibits extension to a subclass.

• Abstract classes contain at least a single abstract method. It serves as a name reservation and forces all subclasses to implement a method with the identical name, parameter list, and return type.

• Interfaces are essentially the same as abstract classes that have no concrete methods, and frequently represent single concepts that are completely abstract at the level they are declared.

• The technique of placing class definitions inside other class definitions is known as using an inner class. The ability to do this allows you to group classes that logically belong together and control data access between classes.

• An anonymous inner class allows you to create a single, local object within an expression by wrapping it in a new method.

• In order to clone and object, you must implement the Cloneable interface.

• When an object is cloned, a new object of the same type is created and the values are then copied from the original object to the new object.

• You must override the clone() method to enable deep cloning of objects.

Advanced OOP

10-24 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Questions 1. True/False: An abstract method should always be declared as final.

2. True/False: When you extend an abstract class, you must implement all of its abstract methods.

3. True/False: Interfaces often contain concrete methods.

4. Why would you use inner classes?

5. What is the problem with using the default clone() method?

6. What does the Object’s equals() method test for?

7. What is a hash code?

Important Methods: equals() and hashCode()

J2SE Professional Skills Development 10-25 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Answers 1. True/False: An abstract method should always be declared as final.

False

2. True/False: When you extend an abstract class, you must implement all of its abstract methods. True

3. True/False: Interfaces often contain concrete methods. False

4. Why would you use inner classes? To group classes that logically belong together and share data.

5. What is the problem with using the default clone() method? It will only copy the reference when copying objects.

6. What does the Object’s equals() method test for? Compares two objects and determines if they are the same object.

7. What is a hash code? It is a unique object identifier derived from the object’s memory address.

Lab 10: Advanced OOP

10-26 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Lab 10: Advanced OOP

Lab 10 Overview

J2SE Professional Skills Development 10-27 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Lab 10 Overview In this lab you’ll learn how to implement inner classes and access their data members. You’ll also discover how to implement the Cloneable interface and clone an object. You’ll then utilize the equals() method and hashCode() method for comparing objects.

To complete this lab, you’ll need to work through two exercises:

• Using Inner Classes

• Cloning an Object

Each exercise includes an “Objective” section that describes the purpose of the exercise. You are encouraged to try to complete the exercise from the information given in the Objective section. If you require more information to complete the exercise, the Objective section is followed by detailed step-by-step instructions.

Lab 10: Advanced OOP

10-28 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Using Inner Classes

Objective In this exercise, you’ll create two inner classes—Author and Subject—that represent a Book object. When the program runs, it will create a Book object. The Book object will have a setBook() method that will create and initialize the Author and Subject objects with its given parameters, and will then print out the book details.

Step-by-Step Instructions 1. Open the Book.java file in this lab’s directory.

2. Create an inner class named Author with two private String member variables named firstName and lastName.

class Author {

private String firstName;

private String lastName;

}

3. Add a constructor to the Author class that accepts two String arguments and a public getName() method to retrieve the author’s name.

Using Inner Classes

J2SE Professional Skills Development 10-29 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

class Author {

private String firstName;

private String lastName;

Author(String fName, String lName) {

this.firstName = fName;

this.lastName = lName;

}

public String getName() {

return firstName + " " + lastName;

}

}

4. Create an inner class named Subject with a private String variable named title and a String array named chapters.

class Subject {

private String title;

private String[] chapters;

}

5. Add a constructor to the Subject class that accepts two arguments and public getTitle() and getChapters() methods, and retrieves the book title and chapters.

Lab 10: Advanced OOP

10-30 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

class Subject {

private String title;

private String[] chapters;

Subject(String title, String[] cNames) {

this.title = title;

this.chapters = cNames;

}

public String getTitle() {

return title;

}

public String getChapters() {

String s = "";

for (int i = 0; i < chapters.length; i++) {

s = s + chapters[i];

if (i < (chapters.length - 1)) {

s = s + ", ";

}

}

return s;

}

}

6. Add a setBook() method to the Book class that creates and initializes the Author and Subject classes and then prints the book details.

public void setBook(String fName, String lName, _

String title, String[] chapters) {

Author author = new Author(fName, lName);

Subject subject = new Subject(title, chapters);

System.out.println("Title: " + subject.getTitle());

System.out.println("Author: " + author.getName());

System.out.println("Chapters: " + _

subject.getChapters());

}

Using Inner Classes

J2SE Professional Skills Development 10-31 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

7. Save, compile, and run the program.

8. The result should look like the following:

Title: Java Foundations

Author: Neal Ford

Chapters: Intro, Install, Syntax, Objects

Lab 10: Advanced OOP

10-32 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

Cloning an Object

Objective In this exercise, you’ll create a simple Dog object that implements the Cloneable interface and overrides the clone() method. When the program is run, a Dog object will be created then cloned to a new Dog object. You will then compare the two Dog objects using the equals() method and print out the results. Then, using the hashCode() method, you will print out the respective hash codes of each dog.

Step-by-Step Instructions

1. Open the CloneLab.java file in this lab’s directory.

2. To the bottom of the file, add a Dog class that implements the Cloneable interface.

class Dog implements Cloneable {

private String name;

Dog(String s) {

this.name = s;

}

public Object clone()

throws CloneNotSupportedException {

return super.clone();

}

}

3. In the main() method, create a new Dog object, and then clone it.

Cloning an Object

J2SE Professional Skills Development 10-33 Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

public class CloneLab {

public static void main(String[] args){

Dog newDog = null;

Dog oldDog = new Dog("Spot");

try {

newDog = (Dog)oldDog.clone();

} catch (CloneNotSupportedException cns) {

}

}

}

4. Using the equals() method, add code to test if the two Dog objects are equal.

public class CloneLab {

public static void main(String[] args){

Dog newDog = null;

Dog oldDog = new Dog("Spot");

try {

newDog = (Dog)oldDog.clone();

} catch (CloneNotSupportedException cns) {

}

if (newDog.equals(oldDog)) {

System.out.println("Equal");

} else {

System.out.println("Not Equal");

}

}

}

Lab 10: Advanced OOP

10-34 J2SE Professional Skills Development Copyright © by Application Developers Training Company and AppDev Products Company, LLC All rights reserved. Reproduction is strictly prohibited.

5. Using the hashCode() method, print the hash code for each of the Dog objects.

public class CloneLab {

public static void main(String[] args){

Dog newDog = null;

Dog oldDog = new Dog("Spot");

try {

newDog = (Dog)oldDog.clone();

} catch (CloneNotSupportedException cns) {

}

if (newDog.equals(oldDog)) {

System.out.println("Equal");

} else {

System.out.println("Not Equal");

}

System.out.println(oldDog.hashCode());

System.out.println(newDog.hashCode());

}

}

6. Save, compile, and run the program.

7. The results should look similar to the following:

Not Equal

7430914

15347198