• 沒有找到結果。

Local Classes

在文檔中 Beginning Java 7Get coding with (頁 143-147)

void speak();

}

class ACDemo {

public static void main(final String[] args) {

new Speakable() {

String msg = (args.length == 1) ? args[0] : "nothing to say";

@Override

public void speak() {

System.out.println(msg);

} }

.speak();

} }

Listing 3-11 is very similar to Listing 3-10. However, instead of subclassing a Speaker class, this listing’s anonymous class implements an interface named Speakable. Apart from the <init>() method calling java.lang.Object() (interfaces have no constructors), Listing 3-11 behaves like Listing 3-10.

Although an anonymous class does not have a constructor, you can provide an instance initializer to handle complex initialization. For example, new Office() {{addEmployee(new Employee("John

Doe"));}}; instantiates an anonymous subclass of Office and adds one Employee object to this instance by calling Office’s addEmployee() method.

You will often find yourself creating and instantiating anonymous classes for their convenience. For example, suppose you need to return a list of all filenames having the “.java” suffix. The following example shows you how an anonymous class simplifies using the java.io package’s File and FilenameFilter classes to achieve this objective:

String[] list = new File(directory).list(new FilenameFilter() {

@Override

public boolean accept(File f, String s) {

return s.endsWith(".java");

} });

Local Classes

A local class is a class that is declared anywhere that a local variable is declared. Furthermore, it has the same scope as a local variable. Unlike an anonymous class, a local class has a name and can be reused.

Like anonymous classes, local classes only have enclosing instances when used in nonstatic contexts.

CHAPTER 3  EXPLORING ADVANCED LANGUAGE FEATURES

A local class instance can access the surrounding scope’s local variables and parameters. However, the local variables and parameters that are accessed must be declared final. For example, Listing 3-12’s local class declaration accesses a final parameter and a final local variable.

Listing 3-12. Declaring a local class class EnclosingClass

{

void m(final int x) {

final int y = x*2;

class LocalClass {

int a = x;

int b = y;

}

LocalClass lc = new LocalClass();

System.out.println(lc.a);

System.out.println(lc.b);

} }

Listing 3-12 declares EnclosingClass with its instance method m() declaring a local class named LocalClass. This local class declares a pair of instance fields (a and b) that are initialized to the values of final parameter x and final local variable y when LocalClass is instantiated: new

EnclosingClass().m(10);, for example.

Listing 3-13 demonstrates this local class.

Listing 3-13. Demonstrating a local class class LCDemo

{

public static void main(String[] args) {

EnclosingClass ec = new EnclosingClass();

ec.m(10);

} }

After instantiating EnclosingClass, Listing 3-13’s main() method invokes m(10). The called m() method multiplies this argument by 2, instantiates LocalClass, whose <init>() method assigns the argument and the doubled value to its pair of instance fields (in lieu of using a constructor to perform this task), and outputs the LocalClass instance fields. The following output results:

10 20

Local classes help improve code clarity because they can be moved closer to where they are needed.

For example, Listing 3-14 declares an Iterator interface and a refactored ToDoList class whose iterator() method returns an instance of its local Iter class as an Iterator instance (because Iter implements Iterator).

CHAPTER 3  EXPLORING ADVANCED LANGUAGE FEATURES

Listing 3-14. The Iterator interface and the refactored ToDoList class interface Iterator

{

boolean hasMoreElements();

Object nextElement();

}

class ToDoList {

private ToDo[] toDoList;

private int index = 0;

ToDoList(int size) {

toDoList = new ToDo[size];

}

Iterator iterator() {

class Iter implements Iterator {

int index = 0;

@Override

public boolean hasMoreElements() {

return index < toDoList.length;

}

@Override

public Object nextElement() {

return toDoList[index++];

} }

return new Iter();

}

void add(ToDo item) {

toDoList[index++] = item;

} }

Listing 3-15 demonstrates Iterator, the refactored ToDoList class, and Listing 3-7’s ToDo class.

Listing 3-15. Creating and iterating over a ToDoList of ToDo instances with a reusable iterator class LCDemo

{

public static void main(String[] args) {

ToDoList toDoList = new ToDoList(5);

toDoList.add(new ToDo("#1", "Do laundry."));

toDoList.add(new ToDo("#2", "Buy groceries."));

toDoList.add(new ToDo("#3", "Vacuum apartment."));

CHAPTER 3  EXPLORING ADVANCED LANGUAGE FEATURES

toDoList.add(new ToDo("#4", "Write report."));

toDoList.add(new ToDo("#5", "Wash car."));

Iterator iter = toDoList.iterator();

while (iter.hasMoreElements())

System.out.println(iter.nextElement());

} }

The Iterator instance that is returned from iterator() returns ToDo items in the same order as when they were added to the list. Although you can only use the returned Iterator object once, you can call iterator() whenever you need a new Iterator object. This capability is a big improvement over the one-shot iterator presented in Listing 3-9.

Interfaces Within Classes

Interfaces can be nested within classes. Once declared, an interface is considered to be static, even if it is not declared static. For example, Listing 3-16 declares an enclosing class named X along with two nested static interfaces named A and B.

Listing 3-16. Declaring a pair of interfaces within a class class X

{

interface A {

}

static interface B {

} }

You would access Listing 3-16’s interfaces in the same way. For example, you would specify class C implements X.A {} or class D implements X.B {}.

As with nested classes, nested interfaces help to implement top-level class architecture by being implemented via nested classes. Collectively, these types are nested because they cannot (as in Listing 3-14’s Iter local class) or need not appear at the same level as a top-level class and pollute its package namespace.

■ Note Chapter 2’s introduction to interfaces showed you how to declare constants and method headers in the

body of an interface. You can also declare interfaces and classes in an interface’s body. Because there are few

good reasons to do this (

java.util.Map.Entry

, which is discussed in Chapter 5, is one exception), it is probably

best to avoid nesting interfaces and/or classes within interfaces.

CHAPTER 3  EXPLORING ADVANCED LANGUAGE FEATURES

Packages

Hierarchical structures organize items in terms of hierarchical relationships that exist between those items. For example, a filesystem might contain a taxes directory with multiple year subdirectories, where each subdirectory contains tax information pertinent to that year. Also, an enclosing class might contain multiple nested classes that only make sense in the context of the enclosing class.

Hierarchical structures also help to avoid name conflicts. For example, two files cannot have the same name in a nonhierarchical filesystem (which consists of a single directory). In contrast, a hierarchical filesystem lets same-named files exist in different directories. Similarly, two enclosing classes can contain same-named nested classes. Name conflicts do not exist because items are partitioned into different namespaces.

Java also supports the partitioning of top-level user-defined types into multiple namespaces, to better organize these types and to also prevent name conflicts. Java uses packages to accomplish these tasks.

This section introduces you to packages. After defining this term and explaining why package names must be unique, the section presents the package and import statements. It next explains how the JVM searches for packages and types, and then presents an example that shows you how to work with packages. This section closes by showing you how to encapsulate a package of classfiles into JAR files.

■ Tip Except for the most trivial of top-level types and (typically) those classes that serve as application entry

points, you should consider storing your types (especially if they are reusable) in packages.

在文檔中 Beginning Java 7Get coding with (頁 143-147)