分享
 
 
 

方法和作用域中的内部类

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

至此,我们已基本理解了内部类的典型用途。对那些涉及内部类的代码,通常表达的都是“单纯”的内部类,非常简单,且极易理解。然而,内部类的设计非常全面,不可避免地会遇到它们的其他大量用法――假若我们在一个方法甚至一个任意的作用域内创建内部类。有两方面的原因促使我们这样做:

(1) 正如前面展示的那样,我们准备实现某种形式的接口,使自己能创建和返回一个句柄。

(2) 要解决一个复杂的问题,并希望创建一个类,用来辅助自己的程序方案。同时不愿意把它公开。

在下面这个例子里,将修改前面的代码,以便使用:

(1) 在一个方法内定义的类

(2) 在方法的一个作用域内定义的类

(3) 一个匿名类,用于实现一个接口

(4) 一个匿名类,用于扩展拥有非默认构建器的一个类

(5) 一个匿名类,用于执行字段初始化

(6) 一个匿名类,通过实例初始化进行构建(匿名内部类不可拥有构建器)

所有这些都在innerscopes包内发生。首先,来自前述代码的通用接口会在它们自己的文件里获得定义,使它们能在所有的例子里使用:

//: Destination.java

package c07.innerscopes;

interface Destination {

String readLabel();

} ///:~

由于我们已认为Contents可能是一个抽象类,所以可采取下面这种更自然的形式,就象一个接口那样:

//: Contents.java

package c07.innerscopes;

interface Contents {

int value();

} ///:~

尽管是含有具体实施细节的一个普通类,但Wrapping也作为它所有衍生类的一个通用“接口”使用:

//: Wrapping.java

package c07.innerscopes;

public class Wrapping {

private int i;

public Wrapping(int x) { i = x; }

public int value() { return i; }

} ///:~

在上面的代码中,我们注意到Wrapping有一个要求使用自变量的构建器,这就使情况变得更加有趣了。

第一个例子展示了如何在一个方法的作用域(而不是另一个类的作用域)中创建一个完整的类:

//: Parcel4.java

// Nesting a class within a method

package c07.innerscopes;

public class Parcel4 {

public Destination dest(String s) {

class PDestination

implements Destination {

private String label;

private PDestination(String whereTo) {

label = whereTo;

}

public String readLabel() { return label; }

}

return new PDestination(s);

}

public static void main(String[] args) {

Parcel4 p = new Parcel4();

Destination d = p.dest("Tanzania");

}

} ///:~

PDestination类属于dest()的一部分,而不是Parcel4的一部分(同时注意可为相同目录内每个类内部的一个内部类使用类标识符PDestination,这样做不会发生命名的冲突)。因此,PDestination不可从dest()的外部访问。请注意在返回语句中发生的上溯造型――除了指向基础类Destination的一个句柄之外,没有任何东西超出dest()的边界之外。当然,不能由于类PDestination的名字置于dest()内部,就认为在dest()返回之后PDestination不是一个有效的对象。

下面这个例子展示了如何在任意作用域内嵌套一个内部类:

//: Parcel5.java

// Nesting a class within a scope

package c07.innerscopes;

public class Parcel5 {

private void internalTracking(boolean b) {

if(b) {

class TrackingSlip {

private String id;

TrackingSlip(String s) {

id = s;

}

String getSlip() { return id; }

}

TrackingSlip ts = new TrackingSlip("slip");

String s = ts.getSlip();

}

// Can't use it here! Out of scope:

//! TrackingSlip ts = new TrackingSlip("x");

}

public void track() { internalTracking(true); }

public static void main(String[] args) {

Parcel5 p = new Parcel5();

p.track();

}

} ///:~

TrackingSlip类嵌套于一个if语句的作用域内。这并不意味着类是有条件创建的――它会随同其他所有东西得到编译。然而,在定义它的那个作用域之外,它是不可使用的。除这些以外,它看起来和一个普通类并没有什么区别。

下面这个例子看起来有些奇怪:

//: Parcel6.java

// A method that returns an anonymous inner class

package c07.innerscopes;

public class Parcel6 {

public Contents cont() {

return new Contents() {

private int i = 11;

public int value() { return i; }

}; // 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);

}

} ///:~

也就是说,我们将适当的自变量简单地传递给基础类构建器,在这儿表现为在“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;

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有