0% found this document useful (0 votes)
5 views7 pages

018 Nested-Classes

Uploaded by

Dorin Togoie
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views7 pages

018 Nested-Classes

Uploaded by

Dorin Togoie
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

Unit 18: Nested classes

Define tightly coupled classes

J Steven Perry September 14, 2016

Learn the structure, syntax, and programming paradigm of the Java platform and language.
Start by mastering the essentials of object-oriented programming on the Java platform, and
progress incrementally to the more-sophisticated syntax and libraries that you need to develop
complex, real-world Java applications.

Before you begin


This unit is part of the "Intro to Java programming" learning path. Although the concepts discussed
in the individual units are standalone in nature, the hands-on component builds as you progress
through the units, and I recommend that you review the prerequisites, setup, and unit details
before proceeding.

Unit objectives
• Know how to define nested classes and when it's appropriate to use them
• Understand the side effects of using nested classes
• Comprehend the special use of new operator with nested classes
• Know how and when to use static inner classes and anonymous inner classes

Where to use nested classes


As its name suggests, a nested class (or inner class) is a class defined within another class:
public class EnclosingClass {
. . .
public class NestedClass {
. . .

}
}

Like member variables and methods, Java classes can also be defined at any scope including
public, private, or protected. Nested classes can be useful when you want to handle internal

© Copyright IBM Corporation 2016 Trademarks


Unit 18: Nested classes Page 1 of 7
developerWorks® ibm.com/developerWorks/

processing within your class in an object-oriented fashion but limit the functionality to the class
where you need it.

Typically, you use a nested class when you need a class that's tightly coupled with the class in
which it's defined. A nested class has access to the private data within its enclosing class, but this
structure carries with it side effects that aren't obvious when you start working with nested classes.

Scope in nested classes


Because a nested class has scope, it's bound by the rules of scope. For example, a member
variable can only be accessed through an instance of the class (an object). The same is true of a
nested class.

Suppose you have the following relationship between a Manager and a nested class called
DirectReports, which is a collection of the Employees that report to that Manager:

public class Manager extends Employee {


private DirectReports directReports;
public Manager() {
this.directReports = new DirectReports();
}
. . .
private class DirectReports {
. . .
}
}

Just as each Manager object represents a unique human being, the DirectReports object
represents a collection of actual people (employees) who report to a manager. DirectReports
differ from one Manager to another. In this case, it makes sense that I would only reference the
DirectReports nested class in the context of its enclosing instance of Manager, so I've made it
private.

Public nested classes


Because it's private, only Manager can create an instance of DirectReports. But suppose you
wanted to give an external entity the ability to create instances of DirectReports. In this case,
it seems like you could give the DirectReports class public scope, and then any external code
could create DirectReports instances, as shown in Listing 1.

Listing 1. Creating DirectReports instances: First attempt


public class Manager extends Employee {
public Manager() {
}
. . .
public class DirectReports {
. . .
}
}
//
public static void main(String[] args) {
Manager.DirectReports dr = new Manager.DirectReports();// This won't work!
}

Unit 18: Nested classes Page 2 of 7


ibm.com/developerWorks/ developerWorks®

The code in Listing 1 doesn't work, and you're probably wondering why. The problem (and also its
solution) lies with the way DirectReports is defined within Manager, and with the rules of scope.

The rules of scope, revisited


If you had a member variable of Manager, you'd expect the compiler to require you to have a
reference to a Manager object before you could reference it, right? Well, the same applies to
DirectReports, at least as it's defined in Listing 1.

To create an instance of a public nested class, you use a special version of the new operator.
Combined with a reference to an enclosing instance of an outer class, new gives you a way you to
create an instance of the nested class:
public class Manager extends Employee {
public Manager() {
}
. . .
public class DirectReports {
. . .
}
}
// Meanwhile, in another method somewhere...
public static void main(String[] args) {
Manager manager = new Manager();
Manager.DirectReports dr = manager.new DirectReports();
}

Note on line 12 that the syntax calls for a reference to the enclosing instance, plus a dot and the
new keyword, followed by the class you want to create.

Static inner classes


At times, you want to create a class that's tightly coupled (conceptually) to a class, but where the
rules of scope are somewhat relaxed, not requiring a reference to an enclosing instance. That's
where static inner classes come into play. One common example is to implement a Comparator,
which is used to compare two instances of the same class, usually for the purpose of ordering (or
sorting) the classes:
public class Manager extends Employee {
. . .
public static class ManagerComparator implements Comparator<Manager> {
. . .
}
}
// Meanwhile, in another method somewhere...
public static void main(String[] args) {
Manager.ManagerComparator mc = new Manager.ManagerComparator();
. . .
}

In this case, you don't need an enclosing instance. Static inner classes act like their regular Java
class counterparts, and you should use them only when you need to couple a class tightly with its
definition. Clearly, in the case of a utility class like ManagerComparator, creating an external class

Unit 18: Nested classes Page 3 of 7


developerWorks® ibm.com/developerWorks/

is unnecessary and potentially clutters up your code base. Defining such classes as static inner
classes is the way to go.

Anonymous inner classes


With the Java language, you can implement abstract classes and interfaces pretty much
anywhere, even in the middle of a method if necessary, and even without providing a name for
the class. This capability is basically a compiler trick, but there are times when anonymous inner
classes are handy to have.

Listing 2 builds on the example in Listing 1 in Unit 17: Interfaces, adding a default method for
handling Employee types that are not StockOptionEligible. The listing starts with a method in
HumanResourcesApplication to process the stock options, followed by a JUnit test to drive the
method.

Listing 2. Handling Employee types that are not StockOptionEligible


// From HumanResourcesApplication.java
public void handleStockOptions(final Person person, StockOptionProcessingCallback callback) {
if (person instanceof StockOptionEligible) {
// Eligible Person, invoke the callback straight up
callback.process((StockOptionEligible)person);
} else if (person instanceof Employee) {
// Not eligible, but still an Employee. Let's cobble up a
/// anonymous inner class implementation for this
callback.process(new StockOptionEligible() {
@Override
public void awardStockOptions(int number, BigDecimal price) {
// This employee is not eligible
log.warning("It would be nice to award " + number + " of shares at $" +
price.setScale(2, RoundingMode.HALF_UP).toPlainString() +
", but unfortunately, Employee " + person.getName() +
" is not eligible for Stock Options!");
}
});
} else {
callback.process(new StockOptionEligible() {
@Override
public void awardStockOptions(int number, BigDecimal price) {
log.severe("Cannot consider awarding " + number + " of shares at $" +
price.setScale(2, RoundingMode.HALF_UP).toPlainString() +
", because " + person.getName() +
" does not even work here!");
}
});
}
}
// JUnit test to drive it (in HumanResourcesApplicationTest.java):
@Test
public void testHandleStockOptions() {
List<Person> people = HumanResourcesApplication.createPeople();

StockOptionProcessingCallback callback = new StockOptionProcessingCallback() {


@Override
public void process(StockOptionEligible stockOptionEligible) {
BigDecimal reallyCheapPrice = BigDecimal.valueOf(0.01);
int numberOfOptions = 10000;
stockOptionEligible.awardStockOptions(numberOfOptions, reallyCheapPrice);
}
};
for (Person person : people) {
classUnderTest.handleStockOptions(person, callback);

Unit 18: Nested classes Page 4 of 7


ibm.com/developerWorks/ developerWorks®

}
}

In the Listing 2 example, I provide implementations of two interfaces that use anonymous
inner classes. First are two separate implementations of StockOptionEligible— one for
Employees and one for Persons (to obey the interface). Then comes an implementation of
StockOptionProcessingCallback that's used to handle processing of stock options for the Manager
instances.

It might take time to grasp the concept of anonymous inner classes, but they're super handy. I use
them all the time in my Java code. And as you progress as a Java developer, I believe you will too.

Test your understanding


1. What is a nested class?
a. A class that provides some utility to other classes in the application
b. A class that is defined within another class
c. A class where one or more interface references are passed into its constructor
d. None of the above
2. Why might you use a nested class?
a. When you need to define a class that is tightly coupled (functionally) with another class
b. When you want to write a class that makes use of a large number of interfaces from the
JDK
c. When one class needs to access to another class private data, but you have exceeded
the maximum number of allowable classes for your application
d. For a class has more than 20 methods defined on it and should be refactored
3. Can you spot the error in the following code? Choose the best answer, explain your choice,
and provide the correct code.
package com.makotojava.intro.quiz;

import java.util.logging.Logger;

public class Outer {

private static final Logger log = Logger.getLogger(Outer.class.getName());

public void setInner(Inner inner) {


this.inner = inner;
}

private Inner inner;

public Inner getInner() {

return inner;
}

private class Inner {


}

public static void main(String[] args) {


Outer outer = new Outer();
Inner inner = new Outer.Inner();
outer.setInner(inner);
log.info("Outer/Inner: " + outer.hashCode() + "/" + outer.getInner().hashCode());

Unit 18: Nested classes Page 5 of 7


developerWorks® ibm.com/developerWorks/

a. The class name Outer is not a legal Java class name.


b. The class name Inner is confusing.
c. The main method defined in class Outer has the wrong method signature.
d. The log.info() call in main() has too many parameters.
e. The class body for class Inner is empty.
f. None of the above.
4. Refer to the code listing in Question 3. Suppose you want a new class called AnotherOuter
in the same package as Outer that could instantiate Outer.Inner. What change(s) would you
need to make to the declaration of Outer.Inner?
a. No changes are necessary; Inner can be instantiated as-is.
b. No inner class can be instantiated outside its enclosing class.
c. Change the visibility of Inner to protected or package-private.
d. Add the static modifier to the Inner class declaration.
e. None of the above.
5. Given the following skeleton, flesh out the main() method to:
1. Instantiate the Hello class
2. Call Hellos talk() method, passing it an instance of HelloCallback implemented as an
anonymous inner class
3. Modify the anonymous inner class implementation of sayHello()to use the Logger
defined on Hello to output:
• "This implementation says: "
• The whatToSay string

import java.util.logging.Logger;

public class Hello {

private static final Logger log = Logger.getLogger(Hello.class.getName());

interface HelloCallback {
void sayHello(String whatToSay);
}

public void talk(HelloCallback helloCallback) {


helloCallback.sayHello("Hello, world (how original :/)...");
}

public static void main(String[] args) {


// YOUR ANSWER GOES HERE
}

}
6. Is it possible to write an inner class that can be instantiated by any class in your application
(regardless of what package in which it resides) without an enclosing instance of the outer
class? Explain your answer.
7. What's the difference between a nested class an an inner class?
a. An inner class is one that is defined using private access only, whereas a nested class is
declared static.

Unit 18: Nested classes Page 6 of 7


ibm.com/developerWorks/ developerWorks®

b. The two terms are synonymous and can be used interchangeably.


c. A nested class must reside inside the enclosing class and be declared before any of the
enclosing class's variables.
d. A nested class is defined in main(), whereas an inner class can be defined anywhere.
e. There is no such thing as a nested class.
f. None of the above.
8. Which of these statements is true regarding inner classes?
a. An inner class can access any private data variables of its enclosing class unless it is
declared static.
b. An inner class must be declared public to be instantiated by any other class than its
enclosing class.
c. A static inner class is not allowed except under special circumstances.
d. An inner class is completely invisible to its enclosing class.
e. None of the above.

Check your answers

For further exploration


The Java Tutorials: Nested Classes

Java - Inner Classes

Java inner class and static nested class

When to use inner classes in Java for helper classes

What are the purposes of inner classes

Previous: Interfaces
Next: Regular expressions

© Copyright IBM Corporation 2016


(www.ibm.com/legal/copytrade.shtml)
Trademarks
(www.ibm.com/developerworks/ibm/trademarks/)

Unit 18: Nested classes Page 7 of 7

You might also like