按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
这儿介绍的方法也允许我们交换使用==或者equals(),就象main()尾部展示的那样。
7。5。4 初始化接口中的字段
接口中定义的字段会自动具有 static 和final 属性。它们不能是“空白 final”,但可初始化成非常数表达
式。例如:
//: RandVals。java
// Initializing interface fields with
// non…constant initializers
import java。util。*;
public interface RandVals {
int rint = (int)(Math。random() * 10);
long rlong = (long)(Math。random() * 10);
float rfloat = (float)(Math。random() * 10);
double rdouble = Math。random() * 10;
} ///:~
由于字段是 static 的,所以它们会在首次装载类之后、以及首次访问任何字段之前获得初始化。下面是一个
简单的测试:
//: TestRandVals。java
public class TestRandVals {
public static void main(String'' args) {
System。out。println(RandVals。rint);
System。out。println(RandVals。rlong);
System。out。println(RandVals。rfloat);
System。out。println(RandVals。rdouble);
}
} ///:~
当然,字段并不是接口的一部分,而是保存于那个接口的 static存储区域中。
178
…………………………………………………………Page 180……………………………………………………………
7。6 内部类
在Java 1。1 中,可将一个类定义置入另一个类定义中。这就叫作“内部类”。内部类对我们非常有用,因为
利用它可对那些逻辑上相互联系的类进行分组,并可控制一个类在另一个类里的“可见性”。然而,我们必
须认识到内部类与以前讲述的“合成”方法存在着根本的区别。
通常,对内部类的需要并不是特别明显的,至少不会立即感觉到自己需要使用内部类。在本章的末尾,介绍
完内部类的所有语法之后,大家会发现一个特别的例子。通过它应该可以清晰地认识到内部类的好处。
创建内部类的过程是平淡无奇的:将类定义置入一个用于封装它的类内部(若执行这个程序遇到麻烦,请参
见第3 章的3。1。2 小节“赋值”):
//: Parcel1。java
// Creating inner classes
package c07。parcel1;
public class Parcel1 {
class Contents {
private int i = 11;
public int value() { return i; }
}
class Destination {
private String label;
Destination(String whereTo) {
label = whereTo;
}
String readLabel() { return label; }
}
// Using inner classes looks just like
// using any other class; within Parcel1:
public void ship(String dest) {
Contents c = new Contents();
Destination d = new Destination(dest);
}
public static void main(String'' args) {
Parcel1 p = new Parcel1();
p。ship(〃Tanzania〃);
}
} ///:~
若在 ship()内部使用,内部类的使用看起来和其他任何类都没什么分别。在这里,唯一明显的区别就是它的
名字嵌套在 Parcel1 里面。但大家不久就会知道,这其实并非唯一的区别。
更典型的一种情况是,一个外部类拥有一个特殊的方法,它会返回指向一个内部类的句柄。就象下面这样:
//: Parcel2。java
// Returning a handle to an inner class
package c07。parcel2;
public class Parcel2 {
class Contents {
private int i = 11;
public int value() { return i; }
}
class Destination {
private String label;
179
…………………………………………………………Page 181……………………………………………………………
Destination(String whereTo) {
label = whereTo;
}
String readLabel() { return label; }
}
public Destination to(String s) {
return new Destination(s);
}
public Contents cont() {
return new Contents();
}
public void ship(String dest) {
Contents c = cont();
Destination d = to(dest);
}
public static void main(String'' args) {
Parcel2 p = new Parcel2();
p。ship(〃Tanzania〃);
Parcel2 q = new Parcel2();
// Defining handles to inner classes:
Parcel2。Contents c = q。cont();
Parcel2。Destination d = q。to(〃Borneo〃);
}
} ///:~
若想在除外部类非 static 方法内部之外的任何地方生成内部类的一个对象,必须将那个对象的类型设为“外
部类名。内部类名”,就象main()中展示的那样。
7。6。1 内部类和上溯造型
迄今为止,内部类看起来仍然没什么特别的地方。毕竟,用它实现隐藏显得有些大题小做。Java 已经有一个
非常优秀的隐藏机制——只允许类成为“友好的”(只在一个包内可见),而不是把它创建成一个内部类。
然而,当我们准备上溯造型到一个基础类(特别是到一个接口)的时候,内部类就开始发挥其关键作用(从
用于实现的对象生成一个接口句柄具有与上溯造型至一个基础类相同的效果)。这是由于内部类随后可完全
进入不可见或不可用状态——对任何人都将如此。所以我们可以非常方便地隐藏实施细节。我们得到的全部
回报就是一个基础类或者接口的句柄,而且甚至有可能不知道准确的类型。就象下面这样:
//: Parcel3。java
// Returning a handle to an inner class
package c07。parcel3;
abstract class Contents {
abstract public int value();
}
interface Destination {
String readLabel();
}
public class Parcel3 {
private class PContents extends Contents {
private int i = 11;
public int value() { return i; }
180
…………………………………………………………Page 182……………………………………………………………
}
protected class PDestination
implements Destination {
private String label;
private PDestination(String whereTo) {
label = whereTo;
}
public String readLabel() { return label; }
}
public Destination dest(String s) {
return new PDestination(s);
}
public Contents cont() {
return new PContents();
}
}
class Test {
public static void main(String'' args) {
Parcel3 p = new Parcel3();
Contents c = p。cont();
Destination d = p。dest(〃Tanzania〃);
// Illegal …can't access private class:
//! Parcel3。PContents c = p。new PContents();
}
} ///:~
现在,