当前位置: 首页 > 工具软件 > Real.java > 使用案例 >

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

仲孙飞文
2023-12-01

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 publicprivate, orprotected. 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.

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

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

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 likeManagerComparator, 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.

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 notStockOptionEligible:


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.

 类似资料:

相关阅读

相关文章

相关问答