按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
}; // Semicolon required in this case
}
public static void main(String'' args) {
Parcel6 p = new Parcel6();
Contents c = p。cont();
}
} ///:~
cont()方法同时合并了返回值的创建代码,以及用于表示那个返回值的类。除此以外,这个类是匿名的——
它没有名字。而且看起来似乎更让人摸不着头脑的是,我们准备创建一个 Contents 对象:
return new Contents()
但在这之后,在遇到分号之前,我们又说:“等一等,让我先在一个类定义里再耍一下花招”:
return new Contents() {
private int i = 11;
public int value() { return i; }
};
这种奇怪的语法要表达的意思是:“创建从 Contents 衍生出来的匿名类的一个对象”。由 new 表达式返回的
句柄会自动上溯造型成一个Contents 句柄。匿名内部类的语法其实要表达的是:
class MyContents extends Contents {
private int i = 11;
public int value() { return i; }
}
return new MyContents();
在匿名内部类中,Contents 是用一个默认构建器创建的。下面这段代码展示了基础类需要含有自变量的一个
构建器时做的事情:
//: Parcel7。java
// An anonymous inner class that calls the
// base…class constructor
package c07。innerscopes;
public class Parcel7 {
public Wrapping wrap(int x) {
// Base constructor call:
return new Wrapping(x) {
public int value() {
return super。value() * 47;
}
}; // Semicolon required
}
public static void main(String'' args) {
Parcel7 p = new Parcel7();
Wrapping w = p。wrap(10);
184
…………………………………………………………Page 186……………………………………………………………
}
} ///:~
也就是说,我们将适当的自变量简单地传递给基础类构建器,在这儿表现为在“new Wrapping(x)”中传递
x。匿名类不能拥有一个构建器,这和在调用 super()时的常规做法不同。
在前述的两个例子中,分号并不标志着类主体的结束(和 C++不同)。相反,它标志着用于包含匿名类的那
个表达式的结束。因此,它完全等价于在其他任何地方使用分号。
若想对匿名内部类的一个对象进行某种形式的初始化,此时会出现什么情况呢?由于它是匿名的,没有名字
赋给构建器,所以我们不能拥有一个构建器。然而,我们可在定义自己的字段时进行初始化:
//: Parcel8。java
// An anonymous inner class that performs
// initialization。 A briefer version
// of Parcel5。java。
package c07。innerscopes;
public class Parcel8 {
// Argument must be final to use inside
// anonymous inner class:
public Destination dest(final String dest) {
return new Destination() {
private String label = dest;
public String readLabel() { return label; }
};
}
public static void main(String'' args) {
Parcel8 p = new Parcel8();
Destination d = p。dest(〃Tanzania〃);
}
} ///:~
若试图定义一个匿名内部类,并想使用在匿名内部类外部定义的一个对象,则编译器要求外部对象为final
属性。这正是我们将dest()的自变量设为final 的原因。如果忘记这样做,就会得到一条编译期出错提示。
只要自己只是想分配一个字段,上述方法就肯定可行。但假如需要采取一些类似于构建器的行动,又应怎样
操作呢?通过Java 1。1 的实例初始化,我们可以有效地为一个匿名内部类创建一个构建器:
//: Parcel9。java
// Using 〃instance initialization〃 to perform
// construction on an anonymous inner class
package c07。innerscopes;
public class Parcel9 {
public Destination
dest(final String dest; final float price) {
return new Destination() {
private int cost;
// Instance initialization for each object:
{
cost = Math。round(price);
if(cost 》 100)
System。out。println(〃Over budget!〃);
}
185
…………………………………………………………Page 187……………………………………………………………
private String label = dest;
public String readLabel() { return label; }
};
}
public static void main(String'' args) {
Parcel9 p = new Parcel9();
Destination d = p。dest(〃Tanzania〃; 101。395F);
}
} ///:~
在实例初始化模块中,我们可看到代码不能作为类初始化模块(即 if语句)的一部分执行。所以实际上,一
个实例初始化模块就是一个匿名内部类的构建器。当然,它的功能是有限的;我们不能对实例初始化模块进
行过载处理,所以只能拥有这些构建器的其中一个。
7。6。3 链接到外部类
迄今为止,我们见到的内部类好象仅仅是一种名字隐藏以及代码组织方案。尽管这些功能非常有用,但似乎
并不特别引人注目。然而,我们还忽略了另一个重要的事实。创建自己的内部类时,那个类的对象同时拥有
指向封装对象(这些对象封装或生成了内部类)的一个链接。所以它们能访问那个封装对象的成员——毋需
取得任何资格。除此以外,内部类拥有对封装类所有元素的访问权限(注释②)。下面这个例子阐示了这个
问题:
//: Sequence。java
// Holds a sequence of Objects
interface Selector {
boolean end();
Object current();
void next();
}
public class Sequence {
private Object'' o;
private int next = 0;
public Sequence(int size) {
o = new Object'size';
}
public void add(Object x) {
if(next 《 o。length) {
o'next' = x;
next++;
}
}
private class SSelector implements Selector {
int i = 0;
public boolean end() {
return i == o。length;
}
public Object current() {
return o'i';
}
public void next() {
if(i 《 o。length) i++;
186
…………………………………………………………Page 188……………………………………………………………
}
}
public Selector getSelector() {
return new SSelector();
}
public static void main(String'' args) {
Sequence s = new Sequence(10);
for(int i = 0; i 《 10; i++)
s。add(Integer。toString(i));
Selector sl = s。getSelector();
whil