您的位置:首页 > 移动开发

Introduction to Java programming, Part 2: Constructs for real-world applications

2011-04-27 00:00 381 查看
http://www.ibm.com/developerworks/java/tutorials/j-introtojava2/section7.html

Nested classes

In this section, learn about nested classes and where and how to use them.

Where to use nested classes

As its name suggests, a nested class is one defined within another class. Here is a nested class:

public class EnclosingClass {
. . .
public class NestedClass {
. . .

}
}

Just 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 processing within your class in an object-oriented fashion, but this functionality is limited to the class where you need it.

Typically, you'll use a nested class for cases where you need a class that is tightly coupled with the class in which it is defined. A nested class has access to the private data within its enclosing class, but this carries with it some side-effects that are not obvious when you start working with nested (or inner) classes.

Back to top
Scope in nested classes

Because a nested class has scope, it is 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
Employee
s 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
will differ from one
Manager
to another. In this case, it makes sense that one 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 17:

Listing 17. Creating DirectReports instances: First attempt

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

The code in Listing 17 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 would 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 you defined it in Listing 17.

To create an instance of a public nested class, you use a special version of the
new
operator. Combined with a reference to some enclosing instance of an outer class,
new
allows you to create an instance of the nested class:

public class Manager extends Employee {
public Manager() {
}
. . .
private class DirectReports {
. . .
}
}
// Meanwhile, in another method somewhere...
public static void main(String[] args) {
Manager manager = new Manager();
Manager.DirectReports dr = manager.new DirectReports();
}

Note 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.

Back to top
Static inner classes

At times you will want to create a class that is 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 of this 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 they should really only be used 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 is unnecessary and potentially clutters up your code base. Defining such classes as static inner classes is the way to go.

Back to top
Anonymous inner classes

The Java language allows you to declare classes pretty much anywhere, even in the middle of a method if necessary, and even without providing a name for the class. This is basically a compiler trick, but there are times when anonymous inner classes are extremely handy to have.

Listing 18 builds on the example in Listing 15, adding a default method for handling
Employee
types that are not
StockOptionEligible
:

Listing 18. Handling
Employee
types that are not
StockOptionEligible


public static void main(String[] args) {
Employee employee = new Manager();// perfectly valid
handleStockOptions(employee);
employee = new Employee();// not StockOptionEligible
handleStockOptions(employee);
}
. . .
private static void handleStockOptions(Employee e) {
if (e instanceof StockOptionEligible) {
calculateAndAwardStockOptions((StockOptionEligible)e);
} else {
calculateAndAwardStockOptions(new StockOptionEligible() {
@Override
public void awardStockOptions(int number, BigDecimal price) {
log.info("Sorry, you're not StockOptionEligible!");
}
});
}
}
. . .
private static void calculateAndAwardStockOptions(StockOptionEligible soe) {
BigDecimal reallyCheapPrice = BigDecimal.valueOf(0.01);
int numberOfOptions = 10000;
soe.processStockOptions(numberOfOptions, reallyCheapPrice);

}

In this example, you provide an implementation of the
StockOptionEligible
interface by using an anonymous inner class for instances of
Employee
that do not implement that interface. Anonymous inner classes are also useful for implementing callback methods, and in event handling, too.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: