原创链接:http://www.blogjava.net/landon/archive/2013/08/05/402357.html
1.内部类
可以将一个类的定义放在另一个类的定义的内部,这就是内部类。
内部类是一种非常有用的特性,因为它允许你把一些逻辑相关的类组织在一起,并控制内部的类的可见性。然而必须了解,内部类与组合是完全不同的概念,这一点很重要。
在最初,内部类看起来就像是一种代码隐藏机制:将类置于其他类的内部。但是你将会了解到,内部类远不止如此。它了解外围类,并与之通信,而且你用内部类写出的代码更加优雅和简洁,尽管不总是这样。
最初,内部类可能看起来有一点奇怪,而且要花些时间才能在设计中轻松使用他们。对内部类的需求并非总是非常明显的,但是在描述完内部类的基本语法和语义后,使用内部类的益处就明确显现了。
2.1.创建内部类
1.创建内部类的方式就如同你想的一样,把类的定义置于外围类的里面。
2.普通的情况下,是在外围类的某个方法中直接使用内部类,不过更为典型的情况是外部类将有一个方法,该方法返回一个指向内部类的引用。
3.如果想从外部类的非静态方法之外的任意位置创建某个类的内部对象,那么就必须具体的指明这个对象的类型,OuterClassName.InnerClassName,如在main方法中的那样。
注:个人认为从例子来看,在static main方法中创建内部类对象引用的是 Parcell2.Destination d = p2.to("Beijing");而在外部类的普通方法中可以直接用,如:
//返回内部类引用的一个方法
public Destination to(String s)
{
return new Destination(s);
}
3.链接到外部类-
到目前为止,内部类似乎还只是一种名字隐藏和组织代码的模式。这些是很有用,不过但还不是最引用注目的,它还有其他的用途。当生成一个内部类的对象时,此对象与制造它的外围对象-enclosing object之间就有了一种联系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外部类的所有元素的访问权。
注:这与C++嵌套类的设计非常不同,在C++中只是单纯的名字隐藏机制,与外围对象没有联系,也没有隐含的访问权。
1.内部类自动拥有对其外围类所有成员的访问权。这是如何做到的呢?当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向外围类对象的引用。然后,在你访问外部类的成员时,就是用那个引用来选择外围类的成员。幸运的是,编译器会帮你处理所有的细节。但你现在可以看到,内部类的对象只能在于其外围类的对象相关联的情况下才会被创建(就像你应该看到的,在内部类是非static类时)。构建内部类对象时,需要一个指向其外围对象的引用,如果编译访问不到这个引用就会报错。不过绝大多数时候,这都无需程序员关心。
4.使用.this与.new
1.如果你需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this,这样产生的引用自动具有正确的类型。这一点在编译期就被知晓被受到检查,因为没有任何运行时开销。
2.有时你想要告知某些其他对象,去创建其某个内部类的对象。要实现此目的,你必须在new表达式中提供对其外部类对象的引用。这就需要.new语法。
注:要想直接创建内部类的对象,你不能按照你想要的方式,去引用外部类的名字DotNew,而是必须使用外部类的对象来创建该内部类的对象。即:
DotNew dn = new DotNew();
//注意这种语法
DotNew.Inner inner = dn.new Inner();
这也解决了内部类名字作用域的问题,因此你不能声明(实际上你不能声明)dn.new DotNew.Innter();在拥有外部类对象之前,是不可能创建内部类对象的。这是因为内部类对象会暗暗的连接到创建它的外部类对象上。但是,如果你创建的是嵌套类(静态内部类),那么它就不需要对外部对象的类引用。
注:个人认为因为内部类对象时连接到它的外部类对象的,所以用dn.new;如果用dn.new DotNew.Innter(),这样的语法形式其实和外部类对象没有关系了。和正常直接创建对象区别不大。正如上面说的,如果你创建的是静态内部类,那么应该就不需要这样了。Java这样的设计其实就是为了区分正常创建对象的方式和内部类创建对象的方式。dn.new Inner()这样的语法,直接说明了Inner是dn的内部类,毋庸置疑。
5.内部类与向上转型:
1.当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就又了用武之地(从实现了某个接口的对象,得到对此接口的引用与向上循转型为这个对象的基类,实际上效果是一样的),这是因为此内部类,某个接口的实现-能够完全不可见,并且不可用(注:因为可以设置内部类的访问修饰符,如private,protected),所得到的只是指向基类或者接口的引用,所以能很方便的隐藏实现细节。
注:将实现了外部接口的内部类修为是private或者protected的话,客户端则根本无法了解或者访问这些成员。注:通常客户端的package和api的package肯定不是同一个,所以也无法访问protected,除非是继承它的子类。因为不能访问这些内部类的名字,所以甚至不能向下转型为private内部类。于是,private内部类给类的设计者提供了一种途径,通过这种方式完全可以阻止任何依赖于类型的编码,并且完全隐藏了实现的细节。此外,从客户端程序员的角度来看,由于不能访问任何新增加的,原本不属于公共接口的方法,所以扩展接口是没有价值的。这也给Java编译器提供了生成更高效的代码的机会。
注:个人认为上面的最后一句话的意思说的就是私有的内部类,扩展了外部接口,不过却没有价值。因为不能被客户端程序员访问。所以Java编译器可以利用这一点,生成高效的代码。
6.在方法和作用域内的内部类
1.可以在一个方法里面或者在任意的作用域内定义内部类。这么做有两个理由:
1.如前所示,你实现了某类型的接口,于是可以创建并返回对其的引用。
2.你要解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类是公共可以用的。
2.注意方法中的局部内部类是属于方法的一部分,而不是类的一部分。所以在方法之外不能访问。当然在方法中定义了内部类,并不意味着一旦该方法执行完毕,该内部类就不可用了。
注:因为在方法中,所以不会出现命名冲突的问题。你可以在同一个子目录的任意类中对某个内部类使用类标识符PDestination.
3.在任意的作用域内嵌入一个内部类,该内部类被嵌入到一个if的作用域内,并不是说该类的创建条件是有条件的,它其实与别的类一起编译过了。然而在定义其出现的作用域之外,它是不可用的。除此之外,它与普通类一样。
7.匿名内部类:
1.匿名类中不可能有命名构造器,因为它根本没名字。
2.public Contents contents()
{
//匿名内部类,匿名,没有名字,创建一个继承自Contents的匿名类的对象.通过new表达式返回的引用被自动向上转型为对Contents的引用
return new Contents()
{
private int i = 3;
@Override
public int value()
{
return i;
}
};
}
3.在2的匿名内部类中,使用了默认的构造器来生成Contents,如果你的基类需要一个有参数的构造器,怎么办?
public Wrapping wrapping(int x)
{
//注意看这里的用法,即使Wrapping是一个普通类,但其还是被其导出类当做”公共接口“来使用
return new Wrapping(x)
{
//更要注意,这里用到了Override关键字,说明返回的这个匿名内部类是Wrapping的一个导出类
@Override
public int value()
{
return super.value() * 3;
}
};//注:这个分号只是标记表达式的结束,只不过这个表达式正巧包含了内部类而已。并不是用来标识此内部类的结束的。因此,这地方与别的地方使用的分号是一致的。
}
4.在匿名类中定义字段时,还能够对其执行初始化操作。如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是final的。如果你忘了,会得到一个编译时错误消息。
5.除了只是简单的字段赋值外,如果想做一些类似构造器的行为,怎么做?因为匿名内部类不可能有命名构造器(因为它根本没名字),但通过实例初始化,就能够做到为匿名内部类创建一个构造器的效果。
注:
1.在匿名内部类使用的参数一定是final的。
2.如果说一个匿名内部类定义的返回的是一个接口,那么注意:return new Interface()...,这里一定是没有参数的。因为我大胆的推断,接口的最原始基类也是Object, 而Object中没有定义含参数的构造函数。
3.注:匿名内部类中实例初始化如果有if相应的判断,则不会被执行。因为他们不能作为字段初始化的一部分来执行。所以对于匿名类来说,实例初始化的实际效果就是构造器。不过其有限制,你不能重载实例初始化方法。所以你仅有一个这样的构造器。
4.匿名内部类与正规的继承相比有些限制,因为匿名内部类即可以扩展类,也可以实现接口。但是不能两者兼备。而且如果是实现接口,也只能实现一个接口。
9.再访工厂方法
1.将工厂作为一个实现的匿名内部类/静态内部类。这样实现的构造函数就可以为private.实现隐藏。同样也没有必要创建作为工厂的具名类。
2.请记住第九章给出的建议:优先使用类而不是接口。如果你的设计需要某个接口,你必须了解它。 否则,不到迫不得已,不要将其放到你的设计中。
10.嵌套类:
1.如果不需要内部类对象与其外围类对象之前有联系,那么可以将内部类声明为static.这通常称为嵌套类。想要理解static应用于内部类的含义,就必须记住。 普通的内部类对象隐式的保存了一个引用,指向创建它的外围类对象。然而,当内部类是static的时候,就不是这样了。嵌套类意味着:
1.要创建嵌套类的对象,并不需要其外围类的对象。
2.不能从嵌套类的对象中访问非静态的外围类对象。
嵌套类与普通的内部类还有一个区别,普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段。也不能包含嵌套类。但是嵌套类可以包含所有这些东西。
注:
1.个人认为因为普通内部类是和外围对象挂钩的,即必须要先创建外围类对象。而static和static字段都是属于类的。即无论有没有外围类的对象,都应该存在或者访问。
2.嵌套类中没有可链接到外围类的this对象,所以这使得它类似一个static方法。
11.接口内部的类
正常情况下,不能在接口内部放置任何代码。但嵌套类可以作为接口的一部分.你放到接口中的任何类都自动是public和static的。因为类是static的,只是将嵌套类置于接口的命名空间内,这并违反接口的规则.你甚至可以在内部类中实现其外围接口。
注:
1.如果你想要创建某些公共代码,使得它们可以被某个接口的所有不同实现所共用,那么使用接口内部的嵌套类会显得很方便。
2.之前作者在建议,在每个类中写一个main方法,用来测试这个类。不过这样做有一个缺点,那就是必须带着那些已编译过的额外代码(注:个人认为这句话的意思是main被编译了,发布产品后也需要有这个东西,但其实这个东西在产品发布后就没有了,所以说是额外的)。如果这对你是一个麻烦的话,那么就可以使用嵌套类来放置测试代码。如TestBed$Tester,要执行这个程序,只需要执行TestBed$Tester即可(UNIX/LINUX中必须转义$)。可以使用这个类做测试,但是不必在发布的产品中包含它。在将产品打包前可以简单的删除TestBed$Tester.class.
12.从多层嵌套类中访问外围类的成员:
1.一个内部类被嵌套多少层不重要,它能透明的访问它所有嵌入的外围类的所有成员。
注:.new语法能产生正确的作用域,所以不必在调用构造器时,限定类名
13.为什么需要内部类?
一般来说,内部类继承自某个类或实现接口。内部类的代码操作创建它的外围类对象。所以可以认为内部类提供了某种进入其外围类的窗口。内部类必须要回答的一个问题是,如果只是需要一个接口的引用,为什么不通过外围类实现那个接口呢?答案是:如果这能满足需求,就应该这样做。那么内部类实现一个接口和外围了实现这个接口有什么区别呢?答案是后者不是总能享用到接口带来的方便。有时需要用到接口的实现。所以使用内部类最吸引人的原因是:
每个内部类都能独立的继承自一个(接口)的实现,所以无论外围类是否已经继承了某个(接口)的实现,对于内部类都没有影响。
如果没有内部类提供的,可以继承多个具体的或者抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变的完整。接口解决了部分问题,而内部类有效地实现了"多重继承"。也就是说,内部类允许继承多个非接口类型,(即类或者抽象类).
注:为了看到更多的细节,我们考虑一种情形,即必须在一个类中以某种方式实现两个接口.由于接口的灵活性,你有两种选择,使用单一类或者内部类:通常遇到问题的时候,问题本身就能给出某些指引,告诉你是应该使用单一类还是使用内部类。但是如果没有其他任何限制,从实现的观点来看,二者没什么不同。
不过如果拥有的是抽象的类或者是具体的类,而不是接口,那么就只能使用内部类才能实现多重继承。
14.如果不需要解决“多重继承”的问题,那么自然就可以用别的方式编码,而不需要使用内部类。但是如果使用内部类,还可以获得一些其他特性:1.内部类可以有多个实例,每个实例都有自己的状态信息.并且与其外围类对象的信息相互独立。
2.在单个内部类中,可以让多个内部类以不同的方式实现同一个接口或者继承自同一个类。
3.创建内部类的对象的时候并不依赖与外围类对象的创建。
4.内部类并没有令人迷惑的is-a关系,它就是一个独立的实体。
15.闭包与回调:
1.闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自创建它的作用域。通过这个定义,可以看出内部类是面向对象的闭包。因为它不仅包含外围类对象(创建内部类的作用域),还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有成员,包括private成员。
2.Java最引人争议的问题之一就是,人们认为Java应该包含某种类似指针的机制,以允许回调(callback).通过回调,对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象。稍后将会看到这是一个非常有用的概念。如果回调是通过指针实现的,那么只能寄望于程序员不会误用该指针。然而,Java语言更小心仔细,所以没有在语言中包括指针。
通过内部类提供闭包的功能是优良的解决方案,它比指针更灵活,更安全。
3.
//传说中的闭包,内部类实现Incrementable
//内部类Closure实现了Incrementable,以提供一个返回Callee2的"钩子"(hook),而且是一个安全的钩子。
private class Closure implements Incrementable
{
@Override
public void increment()
{
//调用外围类的increment方法
Callee2.this.increment();
}
}
//得到回调的引用,提供了一个对外的接口,这里要用接口
//无论谁获得此Incrementable引用,都只能调用increment.除此之外,没有其他功能。不像指针那样,允许你做很多事情
Incrementable getCallBackReference()
{
return new Closure();
}
//Caller的构造器需要一个Incrementable引用作为参数(虽然可以在任何时刻捕获回调引用),然后在以后的某个时刻,Caller对象可以使用此引用回调Callee类
Caller(Incrementable i)
{
callbackReference = i;
}
注:上面的例子因为Caller2继承了MyIncrement,而Caller需要Incrementable对象。当然Caller2也可以实现接口Incrementable.不过因为MyIncrement和Incrementable都有increment方法。不能为了Incrementable的用途覆盖increment方法,所以选择用内部类独立的实现Incrementable接口。这样Caller就可以根据一个Incrementable参数回调Callee.
回调的价值在于它的灵活性。可以在运行时动态的决定需要调用什么方法。在实现GUI功能的时候,都出都用到了回调。
16.内部类与控制框架
1.应用程序框架就是被设计用来解决某类特定问题的一个类或一组类。要运用某个应用程序框架,通常是继承一个或多个类,并覆盖某些方法。在覆盖后的方法中,编写代码定制应用程序框架提供的通用解决方案,以解决你的特定问题。这是设计模式模板方法的一个例子。模板方法包含算法的基本结构,并且会调用一个或多个可覆盖方法,以完成算法的动作。设计模式总是将变化的事物与保持不变的事物分开,在这个模式中,模板方式是保持不变的事物,而可覆盖的方法就是变化的事物。
控制框架是一类特殊的应用程序框架,它用来解决响应事件的需求。主要用来响应事件的系统被称为事件驱动系统。应用程序设计中最常见的问题之一是图形用户接口。它几乎是完全是事件驱动的系统。Java Swing库就是一个控制框架,它优雅的解决了GUI的问题,并使用了大量的内部类。
考虑这样一个控制框架:
它的工作就是在事件就绪的时候执行事件。虽然就绪可以指任何事,不过本例中是指基于时间触发的事件。对于要控制什么,控制框架并不包含任何具体的信息。那些信息是在实现算法的action()部分时,通过继承来提供的。
2.//用来管理并触发事件的实际控制框架
//这就是一个框架,你不知道Event到底做了什么。这正是关键是所在。使变化的事物与不变的事物相互分离。而变化的则是各种不同的Event对象所
//具有的不同行为,而你通过创建不同的Event子类来表现不同的行为。
class Controller
{
//事件列表
private List<Event> eventList = new ArrayList<Event>();
//加入事件
public void addEvent(Event e)
{
eventList.add(e);
}
public void run()
{
//注意这里要copy一个新的eventList,因为下面会有删除操作;否则会造成并发修改
for(Event e : new ArrayList<Event>(eventList))
{
//需要就绪要运行的Event对象
if(e.ready())
{
System.out.println(e);
e.action();
eventList.remove(e);
}
}
}
}
这就是内部类要做的事情,内部类允许:
1.控制框架的完整实现是由单个的类创建的,从而使实现的细节被封装了起来。内部类用来表示解决问题所必须的各种不同的action.
2.内部类能够很容易的访问外围类的任意成员,所有可以避免这种实现变的笨拙。如果没有这种能力,代码会变得非常讨厌。以至于你肯定会选择别的办法。
17.内部类的继承:
1.因为内部类的构造器必须连接到指向其外围类对象的引用.所以在继承内部类的时候,事情变的有些复杂。问题在于,那个指向外围类对象的秘密的引用必须被初始化。而在导出类中不再存在可连接的默认对象。要解决这个问题,必须要用特殊的语法来明确说清他们之前的关联。
2.public class InheriInner extends WithInner.Inner
{
//继承WithInnte的内部类
public InheriInner(WithInner wi)
{
//必须要使用这样的语法,这样特殊的语法.
//不能只传递一个指向外围类的引用。此外,还必须在构造器中使用.super语法
//注:个人认为1.需要调用InheriInner基类的构造函数,正常情况下应该是super
//2不过由于其基类是和一个外围类引用挂钩的。所以采用wi.super()的语法。和wi.new语法恰恰相反。.
wi.super();
}
}
18.内部类可以被覆盖吗?
1.当继承了某个外围类的时候,内部类并没有发生什么特别神奇的变化。这两个内部类是完全独立的两个实体,各自在自己的命名空间内。当然可以明确的继承某个内部类也是可以的。
19.局部内部类
1.可以在代码里创建内部类,典型的方式是在一个方法体里面创建。局部内部类不能有访问说明符,因为它不是外围类的一部分。但是它可以访问当前代码块内的常量以及外围类的所有成员。
2.使用局部内部类和匿名内部类实现了同样的功能,既然局部内部类的名字在方法外是不可见的,那为什么我们仍然使用局部内部类而不是匿名内部类呢?唯一的理由是,我们需要以命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例初始化。
所以使用局部内部类而不使用匿名内部类的另一个理由是,需要不止一个该内部类对象。
20.内部类标识符:
1.由于每一个类都会产生一个.class文件,其中包含了如何创建该类型对象的全部信息。(此信息产生一个"meta-class",叫做CLass对象).内部类也必须生成一个.class文件以包含它们的Class对象信息。这些类文件的命名有严格的规则,外围类的名字,加上$,再加上内部类的名字。如果内部类是匿名的,编译器则会简单的产生一个数字作为其标识符。如果内部类是嵌套在别的内部类中,只需直接将它们的名字加在其外围类标识符与$的后面。
注:对于Unix shell来说,$是一个元字符。所在在列出.class文件的时候,有时会有问题。
虽然这种命名格式简单而直接,但它还是很健壮的,足以应对绝大多数情况。见注。因为这是Java的标准命名方式。所以产生的文件自动都是平台无关的。注意,为了保证你的内部类能其作用。Java编译器会尽可能转换他们。
部分源码:
package com.book.chapter10.innerClass;
/**
*
*匿名类的”构造函数“
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class AnonymousConstructor
{
//注意该类中不一定要求i是final的,因为i被传递给匿名内部类的基类的构造器,并不会在匿名内部类被直接使用。
public static Base getBase(int i)
{
return new Base(i)
{
//这相当于普通类中的实例初始化块
{System.out.println("Inside instance initializer");}
@Override
public void f()
{
System.out.println("In Anonymous f()");
}
};
}
public static void main(Stringargs)
{
Base base = getBase(3);
base.f();
}
}
//一个抽象类Base
abstract class Base
{
//抽象类的构造函数
public Base(int i)
{
System.out.println("Base Constructor,i = " + i);
}
public abstract void f();
}
package com.book.chapter10.innerClass;
/**
*
*测试内部类的继承/覆盖问题
*输出结果:
*New Egg()
*Egg.Yolk()
*从输出结果可以看出,基类和子类的同名内部类没有一毛钱关系
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-6-4
*
*/
public class BigEgg extends Egg//继承Egg
{
//和基类中同名的一个内部类Yolk
public class Yolk
{
public Yolk()
{
System.out.println("BigEgg.Yolk()");
}
}
public static void main(Stringargs)
{
//会默认调用基类的构造器
new BigEgg();
}
}
class Egg
{
private Yolk y;
//内部类-蛋黄-protected
protected class Yolk
{
public Yolk()
{
System.out.println("Egg.Yolk()");
}
}
public Egg()
{
System.out.println("New Egg()");
y = new Yolk();
}
}
package com.book.chapter10.innerClass;
/**
*
*测试子类内部类可以继承基类内部类
*注:注意此类的输出结果:
*1.Egg2 e2 = new BigEgg2()->首先调用基类的构造函数->首先执行基类的成员初始化private Yolk y = new Yolk()->输出Egg2.Yolk()
*2.然后执行基类的构造函数->输出New Egg2()
*3.然后执行子类的构造函数->insertYok(new Yolk())->执行Yolk的构造函数->调用Yolk基类的构造函数->输出Egg2.Yolk()
*4.调用子类Yolk的构造函数->输出BigEgg2.Yolk()
*5.调用e2.g->执行子类Yolk的f方法->输出BigEgg2.Yolk.f()
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-6-4
*
*/
public class BigEgg2 extends Egg2
{
//显示的继承基类的内部类
public class Yolk extends Egg2.Yolk
{
public Yolk()
{
System.out.println("BigEgg2.Yolk()");
}
@Override
public void f()
{
System.out.println("BigEgg2.Yolk.f()");
}
}
public BigEgg2()
{
insertYok(new Yolk());
}
public static void main(Stringargs)
{
Egg2 e2 = new BigEgg2();
e2.g();
}
}
class Egg2
{
//内部类Yolk
protected class Yolk
{
public Yolk()
{
System.out.println("Egg2.Yolk()");
}
public void f()
{
System.out.println("Egg2.Yolk.f()");
}
}
private Yolk y = new Yolk();
public Egg2()
{
System.out.println("New Egg2()");
}
public void insertYok(Yolk yy)
{
y = yy;
}
public void g()
{
//调用内部类的f方法
y.f();
}
}
package com.book.chapter10.innerClass;
/**
*
*测试Java回调/闭包的概念
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-29
*
*/
public class Callbacks
{
public static void main(Stringargs)
{
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.f(c2);
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallBackReference());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
}
//接口Incrementable
interface Incrementable
{
void increment();
}
//Calleel简单的实现了接口Incrementable,被调用者1
class Callee1 implements Incrementable
{
private int i = 0;
@Override
public void increment()
{
i++;
System.out.println(i);
}
}
class MyIncrement
{
//一个和Incrementable完全不同的
public void increment()
{
System.out.println("Other Operation");
}
static void f(MyIncrement mi)
{
mi.increment();
}
}
//继承普通类MyInrement,被调用者2
class Callee2 extends MyIncrement
{
private int i = 0;
//覆写了increment方法
@Override
public void increment()
{
super.increment();
i++;
System.out.println(i);
}
//传说中的闭包,内部类实现Incrementable
//内部类Closure实现了Incrementable,以提供一个返回Callee2的"钩子"(hook),而且是一个安全的钩子。
private class Closure implements Incrementable
{
@Override
public void increment()
{
//调用外围类的increment方法
Callee2.this.increment();
}
}
//得到回调的引用,提供了一个对外的接口,这里要用接口
//无论谁获得此Incrementable引用,都只能调用increment.除此之外,没有其他功能。不像指针那样,允许你做很多事情
Incrementable getCallBackReference()
{
return new Closure();
}
}
//调用者
class Caller
{
private Incrementable callbackReference;
//Caller的构造器需要一个Incrementable引用作为参数(虽然可以在任何时刻捕获回调引用),然后在以后的某个时刻,Caller对象可以使用此引用回调Callee类
Caller(Incrementable i)
{
callbackReference = i;
}
void go()
{
callbackReference.increment();
}
}
package com.book.chapter10.innerClass;
/**
*
*测试接口中的内部类
*
*<p>注:运行此main,需要右键Run As->Run Configurations,找到Main class:ClassInInterface$Test</p>
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-28
*
*/
public interface ClassInInterface
{
void howdy();
//接口中的内部类,而且实现了外围接口
class Test implements ClassInInterface
{
@Override
public void howdy()
{
System.out.println("howdy");
}
public static void main(Stringargs)
{
new Test().howdy();
}
}
}
package com.book.chapter10.innerClass;
/**
*
*内部类中的.new语法
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-17
*
*/
public class DotNew
{
public class Inner
{
}
public static void main(Stringargs)
{
DotNew dn = new DotNew();
//注意这种语法
DotNew.Inner inner = dn.new Inner();
//注意这种语法是错误的:
//Cannot allocate the member type DotNew.Inner using its compound name when qualified by an enclosing instance.
//The member type name is resolved relatively to the qualifying instance type
//DotNew.Inner inner2 = dn.new DotNew.Inner();
}
}
package com.book.chapter10.innerClass;
/**
*
*内部类的.this用法
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-17
*
*/
public class DotThis
{
void f()
{
System.out.println("DotThis.f()");
}
public class Inner
{
public DotThis outer()
{
//注意这种用法,返回外围的引用
return DotThis.this;
//注:原始的this是返回Inner的this
}
}
public Inner getInner()
{
return new Inner();
}
public static void main(Stringargs)
{
DotThis dt = new DotThis();
//注意下面两种调用都可
DotThis.Inner dti = dt.getInner();
//这样写的话,编译器会默认加上DotThis.Inner
Inner dti2 = dt.getInner();
dti.outer().f();
}
}
package com.book.chapter10.innerClass;
/**
*
*使用内部类来实现工厂方法
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Factories
{
public static void serviceConsumer(ServiceFactory factory)
{
Service service = factory.getService();
service.method1();
service.method2();
}
public static void main(Stringargs)
{
//直接调用实现的静态工厂
serviceConsumer(Implementation1.factory);
serviceConsumer(Implementation2.factory);
}
}
//服务接口
interface Service
{
void method1();
void method2();
}
//服务工厂接口
interface ServiceFactory
{
//获取具体的服务
Service getService();
}
//服务实现1
class Implementation1 implements Service
{
//私有的构造函数,因为在内部的匿名工厂类中返回了,对外隐藏
private Implementation1()
{
}
@Override
public void method1()
{
System.out.println("Implementation1 method1");
}
@Override
public void method2()
{
System.out.println("Implementation1 method2");
}
//匿名内部类实现工厂
public static ServiceFactory factory = new ServiceFactory()
{
@Override
public Service getService()
{
return new Implementation1();
}
};
}
//服务实现2
class Implementation2 implements Service
{
//私有的构造函数,因为在内部的匿名工厂类中返回了,对外隐藏
private Implementation2()
{
}
@Override
public void method1()
{
System.out.println("Implementation2 method1");
}
@Override
public void method2()
{
System.out.println("Implementation2 method2");
}
//匿名内部类实现工厂
public static ServiceFactory factory = new ServiceFactory()
{
@Override
public Service getService()
{
return new Implementation2();
}
};
}
package com.book.chapter10.innerClass;
/**
*
*使用匿名内部类改进工厂的另一个例子
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Games
{
public static void playGame(GameFactory factory)
{
Game game = factory.getGame();
while(game.move())
{
}
}
public static void main(Stringargs)
{
//这里直接传的是实现中的静态工厂
playGame(Chess.factory);
playGame(Checkers.factory);
}
}
//Game接口
interface Game
{
boolean move();
}
//Game
interface GameFactory
{
Game getGame();
}
//Game的实现
class Checkers implements Game
{
//私有
private Checkers()
{
}
private int moves = 0;
private static final int MOEVES = 3;
@Override
public boolean move()
{
System.out.println("Checkers move " + moves);
return ++moves != MOEVES;
}
//匿名内部类--工厂
public static GameFactory factory = new GameFactory()
{
@Override
public Game getGame()
{
return new Checkers();
}
};
}
//Game的实现
class Chess implements Game
{
//私有
private Chess()
{
}
private int moves = 0;
private static final int MOEVES = 4;
@Override
public boolean move()
{
System.out.println("Chess move " + moves);
return ++moves != MOEVES;
}
//匿名内部类--工厂
public static GameFactory factory = new GameFactory()
{
@Override
public Game getGame()
{
return new Chess();
}
};
}
package com.book.chapter10.innerClass;
import java.util.ArrayList;
import java.util.List;
/**
*
*测试内部类在控制框架中的应用->控制框架的一个具体实现,控制温室的运作
*使用内部类,可以在单一的类里面产生对同一个基类Event的多个导出版本。对于温室系统的每一种行为,
*都继承一个新的Event内部类,并且在要实现的action中编写控制代码。
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-31
*
*/
public class GreenHouseController extends Controller
{
public static void main(Stringargs)
{
GreenHouseController gc = new GreenHouseController();
//添加一个响铃事件
gc.addEvent(gc.new Bell(900));
Event[] eventList =
{
gc.new ThermostatNight(0),
gc.new LightOn(200),
gc.new LightOff(400),
gc.new WaterOn(600),
gc.new WaterOff(800),
gc.new ThermostatDay(1000)
};
gc.addEvent(gc.new Restart(2000, eventList));
if(args.length == 1)
{
gc.addEvent(new GreenHouseController.Terminate(Integer.parseInt(args[0])));
}
//运行控制器
gc.run();
}
private boolean light = false;
//灯光开的事件
public class LightOn extends Event
{
public LightOn(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为开灯
light = true;
}
@Override
public String toString()
{
return "Light is on";
}
}
//灯光关的事件
public class LightOff extends Event
{
public LightOff(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为关灯
light = false;
}
@Override
public String toString()
{
return "Light is off";
}
}
private boolean water = false;
//水开的事件
public class WaterOn extends Event
{
public WaterOn(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为开水
water = true;
}
@Override
public String toString()
{
return "Water is on";
}
}
//水关的事件
public class WaterOff extends Event
{
public WaterOff(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为关水
water = false;
}
@Override
public String toString()
{
return "Water is off";
}
}
private String thermoStat = "Day";
//夜晚温度控制事件
public class ThermostatNight extends Event
{
public ThermostatNight(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为夜控
thermoStat = "Night";
}
@Override
public String toString()
{
return "Night Setting";
}
}
//白天温度控制事件
public class ThermostatDay extends Event
{
public ThermostatDay(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为夜控
thermoStat = "Day";
}
@Override
public String toString()
{
return "Day Setting";
}
}
//响铃事件
public class Bell extends Event
{
public Bell(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//添加了一个响铃事件
addEvent(new Bell(delayTime));
}
@Override
public String toString()
{
return "Bing!";
}
}
//重启事件
public class Restart extends Event
{
private Event[] eventList;
public Restart(long dalayTime,Event[] eventList)
{
super(dalayTime);
this.eventList = eventList;
for(Event e : eventList)
{
addEvent(e);
}
}
@Override
//执行重启动作
public void action()
{
for(Event e : eventList)
{
e.start();//重新运行事件
addEvent(e);//因为之前已经被remove后,这里再加上
}
start();//重新运行本事件
addEvent(this);
}
@Override
public String toString()
{
return "restarting system";
}
}
//终止事件,注为static,嵌套类
public static class Terminate extends Event
{
public Terminate(long dalayTime)
{
super(dalayTime);
}
public void action()
{
System.exit(0);
}
@Override
public String toString()
{
return "Terminating";
}
}
}
//要控制的事件,其默认的行为是基于时间去执行控制
abstract class Event
{
//事件开始的时间
private long eventTime;
//时间开始前延迟的时间
protected final long delayTime;
public Event(long delayTime)
{
this.delayTime = delayTime;
}
//开始,设置事件时间,通过调用这个方法也可以重新启动计时器,restarting
public void start()
{
eventTime = System.nanoTime() + delayTime;
}
//判断是否准备好
public boolean ready()
{
return System.nanoTime() >= eventTime;
}
public abstract void action();
}
//用来管理并触发事件的实际控制框架
//这就是一个框架,你不知道Event到底做了什么。这正是关键是所在。使变化的事物与不变的事物相互分离。而变化的则是各种不同的Event对象所
//具有的不同行为,而你通过创建不同的Event子类来表现不同的行为。
class Controller
{
//事件列表
private List<Event> eventList = new ArrayList<Event>();
//加入事件
public void addEvent(Event e)
{
eventList.add(e);
}
public void run()
{
//注意这里要copy一个新的eventList,因为下面会有删除操作;否则会造成并发修改
for(Event e : new ArrayList<Event>(eventList))
{
//需要就绪要运行的Event对象
if(e.ready())
{
System.out.println(e);
e.action();
eventList.remove(e);
}
}
}
}
package com.book.chapter10.innerClass;
/**
*
*继承内部类-使用特殊的语法
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-31
*
*/
public class InheriInner extends WithInner.Inner
{
//继承WithInnte的内部类
public InheriInner(WithInner wi)
{
//必须要使用这样的语法,这样特殊的语法.
//不能只传递一个指向外围类的引用。此外,还必须在构造器中使用.super语法
//注:个人认为1.需要调用InheriInner基类的构造函数,正常情况下应该是super
//2不过由于其基类是和一个外围类引用挂钩的。所以采用wi.super()的语法。和wi.new语法恰恰相反。.
wi.super();
}
}
class WithInner
{
//内部类
class Inner
{
}
}
package com.book.chapter10.innerClass;
/**
*
*测试局部内部类与匿名内部类创建的比较
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-6-4
*
*/
public class LocalInnerClass
{
private int count = 0;
//使用局部内部类实现
Counter getCounter(final String name)
{
//声明局部内部类
class LocalCounter implements Counter
{
//局部内部类可以有构造函数
public LocalCounter()
{
System.out.println("Local Counter");
}
@Override
public int next()
{
//访问局部变量name
System.out.print(name + " ");
//访问外围类成员count
return count++;
}
}
return new LocalCounter();
}
//使用匿名内部类实现同样的功能
Counter getCounter2(final String name)
{
return new Counter()
{
//注意,匿名内部类没有构造函数,只能有实例初始化器
{
System.out.println("Counter");
}
@Override
public int next()
{
System.out.print(name + " ");
return count++;
}
};
}
public static void main(Stringargs)
{
LocalInnerClass lic = new LocalInnerClass();
Counter c1 = lic.getCounter("Local Inner");
Counter c2 = lic.getCounter2("Anonymous Inner");
for(int i = 0;i < 3;i++)
{
System.out.println(c1.next());
}
for(int i = 0;i < 3;i++)
{
System.out.println(c2.next());
}
}
}
interface Counter
{
int next();
}
package com.book.chapter10.innerClass;
/**
*
*在一个类中,以某中方式实现两个接口,两种方式,一种是使用单一类,另一种是使用内部类
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-28
*
*/
public class MultiInterfaces
{
static void takesA(A a)
{
}
static void takesB(B b)
{
}
public static void main(Stringargs)
{
takesA(new X());
takesA(new Y());
takesB(new X());
takesB(new Y().makeB());
}
}
//A接口
interface A
{
}
//B接口
interface B
{
}
//第一种方式,实现两个接口,就是单一类
class X implements A,B
{
}
//第二种方式,使用内部类
class Y implements A
{
B makeB()
{
//使用匿名内部类
return new B()
{
};
}
}
package com.book.chapter10.innerClass;
/**
*
*多层嵌套类中访问外围类的成员
*展示从不同的类里创建多层嵌套的内部类对象的语法。
*.new语法能产生正确的作用域,所以不必在调用构造器时,限定类名
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-28
*
*/
public class MultiNestingAccess
{
public static void main(Stringargs)
{
MNA mna = new MNA();
//创建mna的内部类A
MNA.A a = mna.new A();
//创建a的内部类B,注意调用方式,需要用a.new
MNA.A.B b = a.new B();
b.h();
}
}
class MNA
{
//私有的f方法
private void f()
{
}
//内部类A
class A
{
//A私有的g方法
private void g()
{
}
//A中的又一个内部类
public class B
{
//可以访问外层的g方法,也可访问最外层的f方法
void h()
{
g();
f();
}
}
}
}
package com.book.chapter10.innerClass;
/**
*
*使用内部类的第一个例子
*
*外围类中方法直接使用内部类
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-16
*
*/
public class Parcel
{
//内部类Contents
class Contents
{
private int i = 3;
public int value()
{
return i;
}
}
//内部类Destination
class Destination
{
private String label;
Destination(String whereTo)
{
label = whereTo;
}
String readLabel()
{
return label;
}
}
//这里使用内部类就像使用其他类一样
//在ship方法中使用内部类,与普通类没有什么不同。在这里,实际的区别就是内部类的名字是嵌套在Parcell的
public void ship(String dest)
{
Contents c = new Contents();
Destination d = new Destination(dest);
System.out.println(d.readLabel());
}
public static void main(Stringargs)
{
Parcel p = new Parcel();
p.ship("China");
}
}
package com.book.chapter10.innerClass;
/**
*
*实例初始化的parcel形式
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Parcel10
{
//注意这里参数必须是final的,因为都需要在匿名内部类中使用
public Destination destination(final String dest,final float price)
{
return new Destination()
{
private int cost;
//实例初始化
{
cost = Math.round(price);
//注意这段代码,即if语句不能作为字段初始化的一部分来执行。所以对于匿名类来说,实例初始化的实际效果就是构造器
if(cost > 100)
{
System.out.println("Over Budget");
}
}
private String label = dest;
@Override
public String readLabel()
{
return label;
}
};
}
public static void main(Stringargs)
{
Parcel10 p10 = new Parcel10();
//传100.3是为了测试,匿名内部类中的实例初始化块中的if语句是否执行
p10.destination("renren", 100.3f);
}
}
package com.book.chapter10.innerClass;
/**
*
*测试内部类之嵌套类-static
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-24
*
*/
public class Parcel11
{
//嵌套类,static
private static class ParcelContents implements Contents
{
private int i = 3;
@Override
public int value()
{
return i;
}
}
//嵌套类,static
protected static class ParcelDestination implements Destination
{
private String label;
private ParcelDestination(String whereTo)
{
label = whereTo;
}
@Override
public String readLabel()
{
return label;
}
//嵌套类中可以有静态方法或静属性
public static void f(){}
static int x = 3;
//又一个静态
static class AnotherLevel
{
public static void f()
{
}
static int x = 10;
}
}
public static Destination destination(String s)
{
return new ParcelDestination(s);
}
public static Contents contents()
{
return new ParcelContents();
}
//main中,没有任何的Parcel11对象是必须的。选择使用了选择static成员的普通语法来调用方法。
public static void main(Stringargs)
{
Contents c = contents();
Destination d = destination("SUN");
}
}
package com.book.chapter10.innerClass;
/**
*
*使用内部类的另一个例子
*
*外围类的方法返回一个指向内部类的引用
*
*如果想从外部类的非静态方法之外的任意位置创建某个类的内部对象,那么就必须具体的指明这个对象的类型,
*OuterClassName.InnerClassName
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-16
*
*/
public class Parcel2
{
//内部类Contents
class Contents
{
private int i = 3;
public int value()
{
return i;
}
}
//内部类Destination
class Destination
{
private String label;
Destination(String whereTo)
{
label = whereTo;
}
String readLabel()
{
return label;
}
}
//返回内部类引用的一个方法
public Destination to(String s)
{
return new Destination(s);
}
//返回内部类应用的另一个方法
public Contents contents()
{
return new Contents();
}
public void ship(String dest)
{
Contents c = new Contents();
Destination d = new Destination(dest);
System.out.println(d.readLabel());
}
public static void main(Stringargs)
{
Parcel2 p1 = new Parcel2();
p1.ship("China");
Parcel2 p2 = new Parcel2();
//注意这里的用法:用以指向内部类的用法
Parcel2.Destination d = p2.to("Beijing");
Parcel2.Contents c = p2.contents();
}
}
package com.book.chapter10.innerClass;
/**
*
*.new语法的继续训练
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-21
*
*/
public class Parcel3
{
//内部类Contents
class Contents
{
private int i = 3;
public int value()
{
return i;
}
}
//内部类Destination
class Destination
{
private String label;
public Destination(String whereTo)
{
label = whereTo;
}
public String readLabel()
{
return label;
}
}
public static void main(Stringargs)
{
Parcel3 p3 = new Parcel3();
//.new 语法
Parcel3.Contents c = p3.new Contents();
Parcel3.Destination d = p3.new Destination("cf");
}
}
package com.book.chapter10.innerClass;
/**
*
*局部内部类使用:本例使用的理由是-你实现了某类型的接口,于是可以创建并返回对其的引用。
*方法中的局部内部类是属于方法的一部分,而不是类的一部分。所以在方法之外不能访问。
*当然在方法中定义了内部类,并不意味着一旦该方法执行完毕,该内部类就不可用了。
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-21
*
*/
public class Parcel5
{
public Destination destination(String s)
{
//方法内的局部内部类,挺nx的用法的,注意PDestination是方法的一部分,而不是Parcell5的一部分,方法之外不能访问。
class PDestination implements Destination
{
private String label;
private PDestination(String s)
{
label = s;
}
public String readLabel()
{
return label;
}
}
return new PDestination(s);
}
public static void main(Stringargs)
{
Parcel5 p5 = new Parcel5();
Destination d = p5.destination("dl");
}
}
package com.book.chapter10.innerClass;
/**
*
*在任意的作用域内嵌入内部类
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-22
*
*/
public class Parcel6
{
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");
System.out.println(ts.getSlip());
}
//不能在作用域之外使用局部内部类TrackingSlip,因为不可见,所以cannot be resolved to a type
// TrackingSlip ts2 = new TrackingSlip("slip2");
}
public void track()
{
internalTracking(true);
}
public static void main(Stringargs)
{
Parcel6 parcel6 = new Parcel6();
parcel6.track();
}
}
package com.book.chapter10.innerClass;
/**
*
*匿名内部类使用的第一个demo
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-22
*
*/
public class Parcel7
{
public Contents contents()
{
//匿名内部类,匿名,没有名字,创建一个继承自Contents的匿名类的对象.通过new表达式返回的引用被自动向上转型为对Contents的引用
return new Contents()
{
private int i = 3;
@Override
public int value()
{
return i;
}
};
}
public static void main(Stringargs)
{
Parcel7 p7 = new Parcel7();
p7.contents();
}
}
package com.book.chapter10.innerClass;
/**
*
*{@link Parcel7}中的匿名内部类是本形式的简化形式
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Parcel7b
{
class MyContents implements Contents
{
private int i = 3;
public int value()
{
return i;
}
}
public Contents contents()
{
return new MyContents();
}
public static void main(Stringargs)
{
Parcel7b p7b = new Parcel7b();
Contents c = p7b.contents();
}
}
package com.book.chapter10.innerClass;
/**
*
*匿名内部类传参数
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Parcel8
{
public Wrapping wrapping(int x)
{
//注意看这里的用法,即使Wrapping是一个普通类,但其还是被其导出类当做”公共接口“来使用
return new Wrapping(x)
{
//更要注意,这里用到了Override关键字,说明返回的这个匿名内部类是Wrapping的一个子类
@Override
public int value()
{
return super.value() * 3;
}
};//注:这个分号只是标记表达式的结束,只不过这个表达式正巧包含了内部类而已。并不是用来标识此内部类的结束的。因此,这地方与别的地方使用的分号是一致的。
}
}
//一个具有实现的普通类
class Wrapping
{
private int i;
public Wrapping(int x)
{
i = x;
}
public int value()
{
return i;
}
}
package com.book.chapter10.innerClass;
/**
*
*在匿名类中定义字段时,还能够对其执行初始化操作。如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,
*那么编译器会要求其参数引用是final的。如果你忘了,会得到一个编译时错误消息。
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Parcel9
{
//注意如果该参数需要在内部类中使用to use,该参数必须是final,因为dest被用在了label的初始化,即给字段赋值
public Destination destination(final String dest)
{
return new Destination()
{
//匿名类中定义了一个字段,并且执行了初始化
private String label = dest;
@Override
public String readLabel()
{
return "";
}
};
}
public static void main(Stringargs)
{
Parcel9 p9 = new Parcel9();
Destination d = p9.destination("final place");
System.out.println(d.readLabel());
}
}
package com.book.chapter10.innerClass;
/**
*
*测试内部类访问外围类成员
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-17
*
*/
public class Sequence
{
//外围对象成员 items
private Object[] items;
private int next = 0;
public Sequence(int size)
{
items = new Object[size];
}
//向items添加
public void add(Object obj)
{
if(next < items.length)
{
items[next++] = obj;
}
}
//私有内部类,顺序的Selector
private class SequenceSelector implements Selector
{
private int i = 0;
//直接访问外围类成员items
@Override
public boolean end()
{
return i == items.length;
}
//直接访问外围类成员items
@Override
public Object current()
{
return items[i];
}
//直接访问外围类成员items
@Override
public void next()
{
if(i < items.length)
{
i++;
}
}
}
public Selector getSelector()
{
return new SequenceSelector();
}
public static void main(Stringargs)
{
Sequence sequence = new Sequence(10);
for(int i = 0;i < 10;i++)
{
sequence.add(Integer.toString(i));
}
//内部类与外围类相关联
Selector selector = sequence.getSelector();
while(!selector.end())
{
System.out.println("Selector.current: " + selector.current() + " ");
selector.next();
}
}
}
//Selector接口,迭代器模式
interface Selector
{
boolean end();
Object current();
void next();
}
package com.book.chapter10.innerClass;
/**
*
*将测试的main方法写在嵌套类中,生成的class为TestBed$Tester.class
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-28
*
*/
public class TestBed
{
public void f()
{
System.out.println("f()");
}
//嵌套的内部类
public static class Tester
{
public static void main(Stringargs)
{
new TestBed().f();
}
}
}
package com.book.chapter10.innerClass;
/**
*
*测试,内部类的向上转型
*可以非常方便的隐藏实现细节,通过将内部类修饰为private或者protected
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-21
*
*/
public class TestParcel
{
public static void main(Stringargs)
{
Parcel4 p4 = new Parcel4();
//外部调用的时候,客户端根本无法知道具体的实现细节是什么,因为内部类无法对客户端不可见
Destination d = p4.destination("bj");
Contents c = p4.contents();
//The type Parcell4.PContents is not visible,下面的调用是错误的.因为PContents不可见。
//Parcell4.PContents pc = p4.new PContents();
}
}
//外部接口Contents
interface Contents
{
int value();
}
//外部接口Destination
interface Destination
{
String readLabel();
}
class Parcel4
{
//私有内部类,继承外部接口Contents
private class PContents implements Contents
{
private int i = 3;
public int value()
{
return i;
}
}
//protected内部类,继承外部接口Destination
protected class PDestination implements Destination
{
private String label;
public PDestination(String whereTo)
{
label = whereTo;
}
public String readLabel()
{
return label;
}
}
//隐藏了内部的实现细节
public Destination destination(String s)
{
return new PDestination(s);
}
//隐藏了内部的实现细节
public Contents contents()
{
return new PContents();
}
}
1.内部类
可以将一个类的定义放在另一个类的定义的内部,这就是内部类。
内部类是一种非常有用的特性,因为它允许你把一些逻辑相关的类组织在一起,并控制内部的类的可见性。然而必须了解,内部类与组合是完全不同的概念,这一点很重要。
在最初,内部类看起来就像是一种代码隐藏机制:将类置于其他类的内部。但是你将会了解到,内部类远不止如此。它了解外围类,并与之通信,而且你用内部类写出的代码更加优雅和简洁,尽管不总是这样。
最初,内部类可能看起来有一点奇怪,而且要花些时间才能在设计中轻松使用他们。对内部类的需求并非总是非常明显的,但是在描述完内部类的基本语法和语义后,使用内部类的益处就明确显现了。
2.1.创建内部类
1.创建内部类的方式就如同你想的一样,把类的定义置于外围类的里面。
2.普通的情况下,是在外围类的某个方法中直接使用内部类,不过更为典型的情况是外部类将有一个方法,该方法返回一个指向内部类的引用。
3.如果想从外部类的非静态方法之外的任意位置创建某个类的内部对象,那么就必须具体的指明这个对象的类型,OuterClassName.InnerClassName,如在main方法中的那样。
注:个人认为从例子来看,在static main方法中创建内部类对象引用的是 Parcell2.Destination d = p2.to("Beijing");而在外部类的普通方法中可以直接用,如:
//返回内部类引用的一个方法
public Destination to(String s)
{
return new Destination(s);
}
3.链接到外部类-
到目前为止,内部类似乎还只是一种名字隐藏和组织代码的模式。这些是很有用,不过但还不是最引用注目的,它还有其他的用途。当生成一个内部类的对象时,此对象与制造它的外围对象-enclosing object之间就有了一种联系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外部类的所有元素的访问权。
注:这与C++嵌套类的设计非常不同,在C++中只是单纯的名字隐藏机制,与外围对象没有联系,也没有隐含的访问权。
1.内部类自动拥有对其外围类所有成员的访问权。这是如何做到的呢?当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向外围类对象的引用。然后,在你访问外部类的成员时,就是用那个引用来选择外围类的成员。幸运的是,编译器会帮你处理所有的细节。但你现在可以看到,内部类的对象只能在于其外围类的对象相关联的情况下才会被创建(就像你应该看到的,在内部类是非static类时)。构建内部类对象时,需要一个指向其外围对象的引用,如果编译访问不到这个引用就会报错。不过绝大多数时候,这都无需程序员关心。
4.使用.this与.new
1.如果你需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this,这样产生的引用自动具有正确的类型。这一点在编译期就被知晓被受到检查,因为没有任何运行时开销。
2.有时你想要告知某些其他对象,去创建其某个内部类的对象。要实现此目的,你必须在new表达式中提供对其外部类对象的引用。这就需要.new语法。
注:要想直接创建内部类的对象,你不能按照你想要的方式,去引用外部类的名字DotNew,而是必须使用外部类的对象来创建该内部类的对象。即:
DotNew dn = new DotNew();
//注意这种语法
DotNew.Inner inner = dn.new Inner();
这也解决了内部类名字作用域的问题,因此你不能声明(实际上你不能声明)dn.new DotNew.Innter();在拥有外部类对象之前,是不可能创建内部类对象的。这是因为内部类对象会暗暗的连接到创建它的外部类对象上。但是,如果你创建的是嵌套类(静态内部类),那么它就不需要对外部对象的类引用。
注:个人认为因为内部类对象时连接到它的外部类对象的,所以用dn.new;如果用dn.new DotNew.Innter(),这样的语法形式其实和外部类对象没有关系了。和正常直接创建对象区别不大。正如上面说的,如果你创建的是静态内部类,那么应该就不需要这样了。Java这样的设计其实就是为了区分正常创建对象的方式和内部类创建对象的方式。dn.new Inner()这样的语法,直接说明了Inner是dn的内部类,毋庸置疑。
5.内部类与向上转型:
1.当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就又了用武之地(从实现了某个接口的对象,得到对此接口的引用与向上循转型为这个对象的基类,实际上效果是一样的),这是因为此内部类,某个接口的实现-能够完全不可见,并且不可用(注:因为可以设置内部类的访问修饰符,如private,protected),所得到的只是指向基类或者接口的引用,所以能很方便的隐藏实现细节。
注:将实现了外部接口的内部类修为是private或者protected的话,客户端则根本无法了解或者访问这些成员。注:通常客户端的package和api的package肯定不是同一个,所以也无法访问protected,除非是继承它的子类。因为不能访问这些内部类的名字,所以甚至不能向下转型为private内部类。于是,private内部类给类的设计者提供了一种途径,通过这种方式完全可以阻止任何依赖于类型的编码,并且完全隐藏了实现的细节。此外,从客户端程序员的角度来看,由于不能访问任何新增加的,原本不属于公共接口的方法,所以扩展接口是没有价值的。这也给Java编译器提供了生成更高效的代码的机会。
注:个人认为上面的最后一句话的意思说的就是私有的内部类,扩展了外部接口,不过却没有价值。因为不能被客户端程序员访问。所以Java编译器可以利用这一点,生成高效的代码。
6.在方法和作用域内的内部类
1.可以在一个方法里面或者在任意的作用域内定义内部类。这么做有两个理由:
1.如前所示,你实现了某类型的接口,于是可以创建并返回对其的引用。
2.你要解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类是公共可以用的。
2.注意方法中的局部内部类是属于方法的一部分,而不是类的一部分。所以在方法之外不能访问。当然在方法中定义了内部类,并不意味着一旦该方法执行完毕,该内部类就不可用了。
注:因为在方法中,所以不会出现命名冲突的问题。你可以在同一个子目录的任意类中对某个内部类使用类标识符PDestination.
3.在任意的作用域内嵌入一个内部类,该内部类被嵌入到一个if的作用域内,并不是说该类的创建条件是有条件的,它其实与别的类一起编译过了。然而在定义其出现的作用域之外,它是不可用的。除此之外,它与普通类一样。
7.匿名内部类:
1.匿名类中不可能有命名构造器,因为它根本没名字。
2.public Contents contents()
{
//匿名内部类,匿名,没有名字,创建一个继承自Contents的匿名类的对象.通过new表达式返回的引用被自动向上转型为对Contents的引用
return new Contents()
{
private int i = 3;
@Override
public int value()
{
return i;
}
};
}
3.在2的匿名内部类中,使用了默认的构造器来生成Contents,如果你的基类需要一个有参数的构造器,怎么办?
public Wrapping wrapping(int x)
{
//注意看这里的用法,即使Wrapping是一个普通类,但其还是被其导出类当做”公共接口“来使用
return new Wrapping(x)
{
//更要注意,这里用到了Override关键字,说明返回的这个匿名内部类是Wrapping的一个导出类
@Override
public int value()
{
return super.value() * 3;
}
};//注:这个分号只是标记表达式的结束,只不过这个表达式正巧包含了内部类而已。并不是用来标识此内部类的结束的。因此,这地方与别的地方使用的分号是一致的。
}
4.在匿名类中定义字段时,还能够对其执行初始化操作。如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是final的。如果你忘了,会得到一个编译时错误消息。
5.除了只是简单的字段赋值外,如果想做一些类似构造器的行为,怎么做?因为匿名内部类不可能有命名构造器(因为它根本没名字),但通过实例初始化,就能够做到为匿名内部类创建一个构造器的效果。
注:
1.在匿名内部类使用的参数一定是final的。
2.如果说一个匿名内部类定义的返回的是一个接口,那么注意:return new Interface()...,这里一定是没有参数的。因为我大胆的推断,接口的最原始基类也是Object, 而Object中没有定义含参数的构造函数。
3.注:匿名内部类中实例初始化如果有if相应的判断,则不会被执行。因为他们不能作为字段初始化的一部分来执行。所以对于匿名类来说,实例初始化的实际效果就是构造器。不过其有限制,你不能重载实例初始化方法。所以你仅有一个这样的构造器。
4.匿名内部类与正规的继承相比有些限制,因为匿名内部类即可以扩展类,也可以实现接口。但是不能两者兼备。而且如果是实现接口,也只能实现一个接口。
9.再访工厂方法
1.将工厂作为一个实现的匿名内部类/静态内部类。这样实现的构造函数就可以为private.实现隐藏。同样也没有必要创建作为工厂的具名类。
2.请记住第九章给出的建议:优先使用类而不是接口。如果你的设计需要某个接口,你必须了解它。 否则,不到迫不得已,不要将其放到你的设计中。
10.嵌套类:
1.如果不需要内部类对象与其外围类对象之前有联系,那么可以将内部类声明为static.这通常称为嵌套类。想要理解static应用于内部类的含义,就必须记住。 普通的内部类对象隐式的保存了一个引用,指向创建它的外围类对象。然而,当内部类是static的时候,就不是这样了。嵌套类意味着:
1.要创建嵌套类的对象,并不需要其外围类的对象。
2.不能从嵌套类的对象中访问非静态的外围类对象。
嵌套类与普通的内部类还有一个区别,普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段。也不能包含嵌套类。但是嵌套类可以包含所有这些东西。
注:
1.个人认为因为普通内部类是和外围对象挂钩的,即必须要先创建外围类对象。而static和static字段都是属于类的。即无论有没有外围类的对象,都应该存在或者访问。
2.嵌套类中没有可链接到外围类的this对象,所以这使得它类似一个static方法。
11.接口内部的类
正常情况下,不能在接口内部放置任何代码。但嵌套类可以作为接口的一部分.你放到接口中的任何类都自动是public和static的。因为类是static的,只是将嵌套类置于接口的命名空间内,这并违反接口的规则.你甚至可以在内部类中实现其外围接口。
注:
1.如果你想要创建某些公共代码,使得它们可以被某个接口的所有不同实现所共用,那么使用接口内部的嵌套类会显得很方便。
2.之前作者在建议,在每个类中写一个main方法,用来测试这个类。不过这样做有一个缺点,那就是必须带着那些已编译过的额外代码(注:个人认为这句话的意思是main被编译了,发布产品后也需要有这个东西,但其实这个东西在产品发布后就没有了,所以说是额外的)。如果这对你是一个麻烦的话,那么就可以使用嵌套类来放置测试代码。如TestBed$Tester,要执行这个程序,只需要执行TestBed$Tester即可(UNIX/LINUX中必须转义$)。可以使用这个类做测试,但是不必在发布的产品中包含它。在将产品打包前可以简单的删除TestBed$Tester.class.
12.从多层嵌套类中访问外围类的成员:
1.一个内部类被嵌套多少层不重要,它能透明的访问它所有嵌入的外围类的所有成员。
注:.new语法能产生正确的作用域,所以不必在调用构造器时,限定类名
13.为什么需要内部类?
一般来说,内部类继承自某个类或实现接口。内部类的代码操作创建它的外围类对象。所以可以认为内部类提供了某种进入其外围类的窗口。内部类必须要回答的一个问题是,如果只是需要一个接口的引用,为什么不通过外围类实现那个接口呢?答案是:如果这能满足需求,就应该这样做。那么内部类实现一个接口和外围了实现这个接口有什么区别呢?答案是后者不是总能享用到接口带来的方便。有时需要用到接口的实现。所以使用内部类最吸引人的原因是:
每个内部类都能独立的继承自一个(接口)的实现,所以无论外围类是否已经继承了某个(接口)的实现,对于内部类都没有影响。
如果没有内部类提供的,可以继承多个具体的或者抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变的完整。接口解决了部分问题,而内部类有效地实现了"多重继承"。也就是说,内部类允许继承多个非接口类型,(即类或者抽象类).
注:为了看到更多的细节,我们考虑一种情形,即必须在一个类中以某种方式实现两个接口.由于接口的灵活性,你有两种选择,使用单一类或者内部类:通常遇到问题的时候,问题本身就能给出某些指引,告诉你是应该使用单一类还是使用内部类。但是如果没有其他任何限制,从实现的观点来看,二者没什么不同。
不过如果拥有的是抽象的类或者是具体的类,而不是接口,那么就只能使用内部类才能实现多重继承。
14.如果不需要解决“多重继承”的问题,那么自然就可以用别的方式编码,而不需要使用内部类。但是如果使用内部类,还可以获得一些其他特性:1.内部类可以有多个实例,每个实例都有自己的状态信息.并且与其外围类对象的信息相互独立。
2.在单个内部类中,可以让多个内部类以不同的方式实现同一个接口或者继承自同一个类。
3.创建内部类的对象的时候并不依赖与外围类对象的创建。
4.内部类并没有令人迷惑的is-a关系,它就是一个独立的实体。
15.闭包与回调:
1.闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自创建它的作用域。通过这个定义,可以看出内部类是面向对象的闭包。因为它不仅包含外围类对象(创建内部类的作用域),还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有成员,包括private成员。
2.Java最引人争议的问题之一就是,人们认为Java应该包含某种类似指针的机制,以允许回调(callback).通过回调,对象能够携带一些信息,这些信息允许它在稍后的某个时刻调用初始的对象。稍后将会看到这是一个非常有用的概念。如果回调是通过指针实现的,那么只能寄望于程序员不会误用该指针。然而,Java语言更小心仔细,所以没有在语言中包括指针。
通过内部类提供闭包的功能是优良的解决方案,它比指针更灵活,更安全。
3.
//传说中的闭包,内部类实现Incrementable
//内部类Closure实现了Incrementable,以提供一个返回Callee2的"钩子"(hook),而且是一个安全的钩子。
private class Closure implements Incrementable
{
@Override
public void increment()
{
//调用外围类的increment方法
Callee2.this.increment();
}
}
//得到回调的引用,提供了一个对外的接口,这里要用接口
//无论谁获得此Incrementable引用,都只能调用increment.除此之外,没有其他功能。不像指针那样,允许你做很多事情
Incrementable getCallBackReference()
{
return new Closure();
}
//Caller的构造器需要一个Incrementable引用作为参数(虽然可以在任何时刻捕获回调引用),然后在以后的某个时刻,Caller对象可以使用此引用回调Callee类
Caller(Incrementable i)
{
callbackReference = i;
}
注:上面的例子因为Caller2继承了MyIncrement,而Caller需要Incrementable对象。当然Caller2也可以实现接口Incrementable.不过因为MyIncrement和Incrementable都有increment方法。不能为了Incrementable的用途覆盖increment方法,所以选择用内部类独立的实现Incrementable接口。这样Caller就可以根据一个Incrementable参数回调Callee.
回调的价值在于它的灵活性。可以在运行时动态的决定需要调用什么方法。在实现GUI功能的时候,都出都用到了回调。
16.内部类与控制框架
1.应用程序框架就是被设计用来解决某类特定问题的一个类或一组类。要运用某个应用程序框架,通常是继承一个或多个类,并覆盖某些方法。在覆盖后的方法中,编写代码定制应用程序框架提供的通用解决方案,以解决你的特定问题。这是设计模式模板方法的一个例子。模板方法包含算法的基本结构,并且会调用一个或多个可覆盖方法,以完成算法的动作。设计模式总是将变化的事物与保持不变的事物分开,在这个模式中,模板方式是保持不变的事物,而可覆盖的方法就是变化的事物。
控制框架是一类特殊的应用程序框架,它用来解决响应事件的需求。主要用来响应事件的系统被称为事件驱动系统。应用程序设计中最常见的问题之一是图形用户接口。它几乎是完全是事件驱动的系统。Java Swing库就是一个控制框架,它优雅的解决了GUI的问题,并使用了大量的内部类。
考虑这样一个控制框架:
它的工作就是在事件就绪的时候执行事件。虽然就绪可以指任何事,不过本例中是指基于时间触发的事件。对于要控制什么,控制框架并不包含任何具体的信息。那些信息是在实现算法的action()部分时,通过继承来提供的。
2.//用来管理并触发事件的实际控制框架
//这就是一个框架,你不知道Event到底做了什么。这正是关键是所在。使变化的事物与不变的事物相互分离。而变化的则是各种不同的Event对象所
//具有的不同行为,而你通过创建不同的Event子类来表现不同的行为。
class Controller
{
//事件列表
private List<Event> eventList = new ArrayList<Event>();
//加入事件
public void addEvent(Event e)
{
eventList.add(e);
}
public void run()
{
//注意这里要copy一个新的eventList,因为下面会有删除操作;否则会造成并发修改
for(Event e : new ArrayList<Event>(eventList))
{
//需要就绪要运行的Event对象
if(e.ready())
{
System.out.println(e);
e.action();
eventList.remove(e);
}
}
}
}
这就是内部类要做的事情,内部类允许:
1.控制框架的完整实现是由单个的类创建的,从而使实现的细节被封装了起来。内部类用来表示解决问题所必须的各种不同的action.
2.内部类能够很容易的访问外围类的任意成员,所有可以避免这种实现变的笨拙。如果没有这种能力,代码会变得非常讨厌。以至于你肯定会选择别的办法。
17.内部类的继承:
1.因为内部类的构造器必须连接到指向其外围类对象的引用.所以在继承内部类的时候,事情变的有些复杂。问题在于,那个指向外围类对象的秘密的引用必须被初始化。而在导出类中不再存在可连接的默认对象。要解决这个问题,必须要用特殊的语法来明确说清他们之前的关联。
2.public class InheriInner extends WithInner.Inner
{
//继承WithInnte的内部类
public InheriInner(WithInner wi)
{
//必须要使用这样的语法,这样特殊的语法.
//不能只传递一个指向外围类的引用。此外,还必须在构造器中使用.super语法
//注:个人认为1.需要调用InheriInner基类的构造函数,正常情况下应该是super
//2不过由于其基类是和一个外围类引用挂钩的。所以采用wi.super()的语法。和wi.new语法恰恰相反。.
wi.super();
}
}
18.内部类可以被覆盖吗?
1.当继承了某个外围类的时候,内部类并没有发生什么特别神奇的变化。这两个内部类是完全独立的两个实体,各自在自己的命名空间内。当然可以明确的继承某个内部类也是可以的。
19.局部内部类
1.可以在代码里创建内部类,典型的方式是在一个方法体里面创建。局部内部类不能有访问说明符,因为它不是外围类的一部分。但是它可以访问当前代码块内的常量以及外围类的所有成员。
2.使用局部内部类和匿名内部类实现了同样的功能,既然局部内部类的名字在方法外是不可见的,那为什么我们仍然使用局部内部类而不是匿名内部类呢?唯一的理由是,我们需要以命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例初始化。
所以使用局部内部类而不使用匿名内部类的另一个理由是,需要不止一个该内部类对象。
20.内部类标识符:
1.由于每一个类都会产生一个.class文件,其中包含了如何创建该类型对象的全部信息。(此信息产生一个"meta-class",叫做CLass对象).内部类也必须生成一个.class文件以包含它们的Class对象信息。这些类文件的命名有严格的规则,外围类的名字,加上$,再加上内部类的名字。如果内部类是匿名的,编译器则会简单的产生一个数字作为其标识符。如果内部类是嵌套在别的内部类中,只需直接将它们的名字加在其外围类标识符与$的后面。
注:对于Unix shell来说,$是一个元字符。所在在列出.class文件的时候,有时会有问题。
虽然这种命名格式简单而直接,但它还是很健壮的,足以应对绝大多数情况。见注。因为这是Java的标准命名方式。所以产生的文件自动都是平台无关的。注意,为了保证你的内部类能其作用。Java编译器会尽可能转换他们。
部分源码:
package com.book.chapter10.innerClass;
/**
*
*匿名类的”构造函数“
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class AnonymousConstructor
{
//注意该类中不一定要求i是final的,因为i被传递给匿名内部类的基类的构造器,并不会在匿名内部类被直接使用。
public static Base getBase(int i)
{
return new Base(i)
{
//这相当于普通类中的实例初始化块
{System.out.println("Inside instance initializer");}
@Override
public void f()
{
System.out.println("In Anonymous f()");
}
};
}
public static void main(Stringargs)
{
Base base = getBase(3);
base.f();
}
}
//一个抽象类Base
abstract class Base
{
//抽象类的构造函数
public Base(int i)
{
System.out.println("Base Constructor,i = " + i);
}
public abstract void f();
}
package com.book.chapter10.innerClass;
/**
*
*测试内部类的继承/覆盖问题
*输出结果:
*New Egg()
*Egg.Yolk()
*从输出结果可以看出,基类和子类的同名内部类没有一毛钱关系
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-6-4
*
*/
public class BigEgg extends Egg//继承Egg
{
//和基类中同名的一个内部类Yolk
public class Yolk
{
public Yolk()
{
System.out.println("BigEgg.Yolk()");
}
}
public static void main(Stringargs)
{
//会默认调用基类的构造器
new BigEgg();
}
}
class Egg
{
private Yolk y;
//内部类-蛋黄-protected
protected class Yolk
{
public Yolk()
{
System.out.println("Egg.Yolk()");
}
}
public Egg()
{
System.out.println("New Egg()");
y = new Yolk();
}
}
package com.book.chapter10.innerClass;
/**
*
*测试子类内部类可以继承基类内部类
*注:注意此类的输出结果:
*1.Egg2 e2 = new BigEgg2()->首先调用基类的构造函数->首先执行基类的成员初始化private Yolk y = new Yolk()->输出Egg2.Yolk()
*2.然后执行基类的构造函数->输出New Egg2()
*3.然后执行子类的构造函数->insertYok(new Yolk())->执行Yolk的构造函数->调用Yolk基类的构造函数->输出Egg2.Yolk()
*4.调用子类Yolk的构造函数->输出BigEgg2.Yolk()
*5.调用e2.g->执行子类Yolk的f方法->输出BigEgg2.Yolk.f()
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-6-4
*
*/
public class BigEgg2 extends Egg2
{
//显示的继承基类的内部类
public class Yolk extends Egg2.Yolk
{
public Yolk()
{
System.out.println("BigEgg2.Yolk()");
}
@Override
public void f()
{
System.out.println("BigEgg2.Yolk.f()");
}
}
public BigEgg2()
{
insertYok(new Yolk());
}
public static void main(Stringargs)
{
Egg2 e2 = new BigEgg2();
e2.g();
}
}
class Egg2
{
//内部类Yolk
protected class Yolk
{
public Yolk()
{
System.out.println("Egg2.Yolk()");
}
public void f()
{
System.out.println("Egg2.Yolk.f()");
}
}
private Yolk y = new Yolk();
public Egg2()
{
System.out.println("New Egg2()");
}
public void insertYok(Yolk yy)
{
y = yy;
}
public void g()
{
//调用内部类的f方法
y.f();
}
}
package com.book.chapter10.innerClass;
/**
*
*测试Java回调/闭包的概念
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-29
*
*/
public class Callbacks
{
public static void main(Stringargs)
{
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.f(c2);
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallBackReference());
caller1.go();
caller1.go();
caller2.go();
caller2.go();
}
}
//接口Incrementable
interface Incrementable
{
void increment();
}
//Calleel简单的实现了接口Incrementable,被调用者1
class Callee1 implements Incrementable
{
private int i = 0;
@Override
public void increment()
{
i++;
System.out.println(i);
}
}
class MyIncrement
{
//一个和Incrementable完全不同的
public void increment()
{
System.out.println("Other Operation");
}
static void f(MyIncrement mi)
{
mi.increment();
}
}
//继承普通类MyInrement,被调用者2
class Callee2 extends MyIncrement
{
private int i = 0;
//覆写了increment方法
@Override
public void increment()
{
super.increment();
i++;
System.out.println(i);
}
//传说中的闭包,内部类实现Incrementable
//内部类Closure实现了Incrementable,以提供一个返回Callee2的"钩子"(hook),而且是一个安全的钩子。
private class Closure implements Incrementable
{
@Override
public void increment()
{
//调用外围类的increment方法
Callee2.this.increment();
}
}
//得到回调的引用,提供了一个对外的接口,这里要用接口
//无论谁获得此Incrementable引用,都只能调用increment.除此之外,没有其他功能。不像指针那样,允许你做很多事情
Incrementable getCallBackReference()
{
return new Closure();
}
}
//调用者
class Caller
{
private Incrementable callbackReference;
//Caller的构造器需要一个Incrementable引用作为参数(虽然可以在任何时刻捕获回调引用),然后在以后的某个时刻,Caller对象可以使用此引用回调Callee类
Caller(Incrementable i)
{
callbackReference = i;
}
void go()
{
callbackReference.increment();
}
}
package com.book.chapter10.innerClass;
/**
*
*测试接口中的内部类
*
*<p>注:运行此main,需要右键Run As->Run Configurations,找到Main class:ClassInInterface$Test</p>
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-28
*
*/
public interface ClassInInterface
{
void howdy();
//接口中的内部类,而且实现了外围接口
class Test implements ClassInInterface
{
@Override
public void howdy()
{
System.out.println("howdy");
}
public static void main(Stringargs)
{
new Test().howdy();
}
}
}
package com.book.chapter10.innerClass;
/**
*
*内部类中的.new语法
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-17
*
*/
public class DotNew
{
public class Inner
{
}
public static void main(Stringargs)
{
DotNew dn = new DotNew();
//注意这种语法
DotNew.Inner inner = dn.new Inner();
//注意这种语法是错误的:
//Cannot allocate the member type DotNew.Inner using its compound name when qualified by an enclosing instance.
//The member type name is resolved relatively to the qualifying instance type
//DotNew.Inner inner2 = dn.new DotNew.Inner();
}
}
package com.book.chapter10.innerClass;
/**
*
*内部类的.this用法
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-17
*
*/
public class DotThis
{
void f()
{
System.out.println("DotThis.f()");
}
public class Inner
{
public DotThis outer()
{
//注意这种用法,返回外围的引用
return DotThis.this;
//注:原始的this是返回Inner的this
}
}
public Inner getInner()
{
return new Inner();
}
public static void main(Stringargs)
{
DotThis dt = new DotThis();
//注意下面两种调用都可
DotThis.Inner dti = dt.getInner();
//这样写的话,编译器会默认加上DotThis.Inner
Inner dti2 = dt.getInner();
dti.outer().f();
}
}
package com.book.chapter10.innerClass;
/**
*
*使用内部类来实现工厂方法
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Factories
{
public static void serviceConsumer(ServiceFactory factory)
{
Service service = factory.getService();
service.method1();
service.method2();
}
public static void main(Stringargs)
{
//直接调用实现的静态工厂
serviceConsumer(Implementation1.factory);
serviceConsumer(Implementation2.factory);
}
}
//服务接口
interface Service
{
void method1();
void method2();
}
//服务工厂接口
interface ServiceFactory
{
//获取具体的服务
Service getService();
}
//服务实现1
class Implementation1 implements Service
{
//私有的构造函数,因为在内部的匿名工厂类中返回了,对外隐藏
private Implementation1()
{
}
@Override
public void method1()
{
System.out.println("Implementation1 method1");
}
@Override
public void method2()
{
System.out.println("Implementation1 method2");
}
//匿名内部类实现工厂
public static ServiceFactory factory = new ServiceFactory()
{
@Override
public Service getService()
{
return new Implementation1();
}
};
}
//服务实现2
class Implementation2 implements Service
{
//私有的构造函数,因为在内部的匿名工厂类中返回了,对外隐藏
private Implementation2()
{
}
@Override
public void method1()
{
System.out.println("Implementation2 method1");
}
@Override
public void method2()
{
System.out.println("Implementation2 method2");
}
//匿名内部类实现工厂
public static ServiceFactory factory = new ServiceFactory()
{
@Override
public Service getService()
{
return new Implementation2();
}
};
}
package com.book.chapter10.innerClass;
/**
*
*使用匿名内部类改进工厂的另一个例子
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Games
{
public static void playGame(GameFactory factory)
{
Game game = factory.getGame();
while(game.move())
{
}
}
public static void main(Stringargs)
{
//这里直接传的是实现中的静态工厂
playGame(Chess.factory);
playGame(Checkers.factory);
}
}
//Game接口
interface Game
{
boolean move();
}
//Game
interface GameFactory
{
Game getGame();
}
//Game的实现
class Checkers implements Game
{
//私有
private Checkers()
{
}
private int moves = 0;
private static final int MOEVES = 3;
@Override
public boolean move()
{
System.out.println("Checkers move " + moves);
return ++moves != MOEVES;
}
//匿名内部类--工厂
public static GameFactory factory = new GameFactory()
{
@Override
public Game getGame()
{
return new Checkers();
}
};
}
//Game的实现
class Chess implements Game
{
//私有
private Chess()
{
}
private int moves = 0;
private static final int MOEVES = 4;
@Override
public boolean move()
{
System.out.println("Chess move " + moves);
return ++moves != MOEVES;
}
//匿名内部类--工厂
public static GameFactory factory = new GameFactory()
{
@Override
public Game getGame()
{
return new Chess();
}
};
}
package com.book.chapter10.innerClass;
import java.util.ArrayList;
import java.util.List;
/**
*
*测试内部类在控制框架中的应用->控制框架的一个具体实现,控制温室的运作
*使用内部类,可以在单一的类里面产生对同一个基类Event的多个导出版本。对于温室系统的每一种行为,
*都继承一个新的Event内部类,并且在要实现的action中编写控制代码。
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-31
*
*/
public class GreenHouseController extends Controller
{
public static void main(Stringargs)
{
GreenHouseController gc = new GreenHouseController();
//添加一个响铃事件
gc.addEvent(gc.new Bell(900));
Event[] eventList =
{
gc.new ThermostatNight(0),
gc.new LightOn(200),
gc.new LightOff(400),
gc.new WaterOn(600),
gc.new WaterOff(800),
gc.new ThermostatDay(1000)
};
gc.addEvent(gc.new Restart(2000, eventList));
if(args.length == 1)
{
gc.addEvent(new GreenHouseController.Terminate(Integer.parseInt(args[0])));
}
//运行控制器
gc.run();
}
private boolean light = false;
//灯光开的事件
public class LightOn extends Event
{
public LightOn(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为开灯
light = true;
}
@Override
public String toString()
{
return "Light is on";
}
}
//灯光关的事件
public class LightOff extends Event
{
public LightOff(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为关灯
light = false;
}
@Override
public String toString()
{
return "Light is off";
}
}
private boolean water = false;
//水开的事件
public class WaterOn extends Event
{
public WaterOn(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为开水
water = true;
}
@Override
public String toString()
{
return "Water is on";
}
}
//水关的事件
public class WaterOff extends Event
{
public WaterOff(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为关水
water = false;
}
@Override
public String toString()
{
return "Water is off";
}
}
private String thermoStat = "Day";
//夜晚温度控制事件
public class ThermostatNight extends Event
{
public ThermostatNight(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为夜控
thermoStat = "Night";
}
@Override
public String toString()
{
return "Night Setting";
}
}
//白天温度控制事件
public class ThermostatDay extends Event
{
public ThermostatDay(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//执行动作为夜控
thermoStat = "Day";
}
@Override
public String toString()
{
return "Day Setting";
}
}
//响铃事件
public class Bell extends Event
{
public Bell(long delayTime)
{
super(delayTime);
}
@Override
public void action()
{
//添加了一个响铃事件
addEvent(new Bell(delayTime));
}
@Override
public String toString()
{
return "Bing!";
}
}
//重启事件
public class Restart extends Event
{
private Event[] eventList;
public Restart(long dalayTime,Event[] eventList)
{
super(dalayTime);
this.eventList = eventList;
for(Event e : eventList)
{
addEvent(e);
}
}
@Override
//执行重启动作
public void action()
{
for(Event e : eventList)
{
e.start();//重新运行事件
addEvent(e);//因为之前已经被remove后,这里再加上
}
start();//重新运行本事件
addEvent(this);
}
@Override
public String toString()
{
return "restarting system";
}
}
//终止事件,注为static,嵌套类
public static class Terminate extends Event
{
public Terminate(long dalayTime)
{
super(dalayTime);
}
public void action()
{
System.exit(0);
}
@Override
public String toString()
{
return "Terminating";
}
}
}
//要控制的事件,其默认的行为是基于时间去执行控制
abstract class Event
{
//事件开始的时间
private long eventTime;
//时间开始前延迟的时间
protected final long delayTime;
public Event(long delayTime)
{
this.delayTime = delayTime;
}
//开始,设置事件时间,通过调用这个方法也可以重新启动计时器,restarting
public void start()
{
eventTime = System.nanoTime() + delayTime;
}
//判断是否准备好
public boolean ready()
{
return System.nanoTime() >= eventTime;
}
public abstract void action();
}
//用来管理并触发事件的实际控制框架
//这就是一个框架,你不知道Event到底做了什么。这正是关键是所在。使变化的事物与不变的事物相互分离。而变化的则是各种不同的Event对象所
//具有的不同行为,而你通过创建不同的Event子类来表现不同的行为。
class Controller
{
//事件列表
private List<Event> eventList = new ArrayList<Event>();
//加入事件
public void addEvent(Event e)
{
eventList.add(e);
}
public void run()
{
//注意这里要copy一个新的eventList,因为下面会有删除操作;否则会造成并发修改
for(Event e : new ArrayList<Event>(eventList))
{
//需要就绪要运行的Event对象
if(e.ready())
{
System.out.println(e);
e.action();
eventList.remove(e);
}
}
}
}
package com.book.chapter10.innerClass;
/**
*
*继承内部类-使用特殊的语法
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-31
*
*/
public class InheriInner extends WithInner.Inner
{
//继承WithInnte的内部类
public InheriInner(WithInner wi)
{
//必须要使用这样的语法,这样特殊的语法.
//不能只传递一个指向外围类的引用。此外,还必须在构造器中使用.super语法
//注:个人认为1.需要调用InheriInner基类的构造函数,正常情况下应该是super
//2不过由于其基类是和一个外围类引用挂钩的。所以采用wi.super()的语法。和wi.new语法恰恰相反。.
wi.super();
}
}
class WithInner
{
//内部类
class Inner
{
}
}
package com.book.chapter10.innerClass;
/**
*
*测试局部内部类与匿名内部类创建的比较
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-6-4
*
*/
public class LocalInnerClass
{
private int count = 0;
//使用局部内部类实现
Counter getCounter(final String name)
{
//声明局部内部类
class LocalCounter implements Counter
{
//局部内部类可以有构造函数
public LocalCounter()
{
System.out.println("Local Counter");
}
@Override
public int next()
{
//访问局部变量name
System.out.print(name + " ");
//访问外围类成员count
return count++;
}
}
return new LocalCounter();
}
//使用匿名内部类实现同样的功能
Counter getCounter2(final String name)
{
return new Counter()
{
//注意,匿名内部类没有构造函数,只能有实例初始化器
{
System.out.println("Counter");
}
@Override
public int next()
{
System.out.print(name + " ");
return count++;
}
};
}
public static void main(Stringargs)
{
LocalInnerClass lic = new LocalInnerClass();
Counter c1 = lic.getCounter("Local Inner");
Counter c2 = lic.getCounter2("Anonymous Inner");
for(int i = 0;i < 3;i++)
{
System.out.println(c1.next());
}
for(int i = 0;i < 3;i++)
{
System.out.println(c2.next());
}
}
}
interface Counter
{
int next();
}
package com.book.chapter10.innerClass;
/**
*
*在一个类中,以某中方式实现两个接口,两种方式,一种是使用单一类,另一种是使用内部类
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-28
*
*/
public class MultiInterfaces
{
static void takesA(A a)
{
}
static void takesB(B b)
{
}
public static void main(Stringargs)
{
takesA(new X());
takesA(new Y());
takesB(new X());
takesB(new Y().makeB());
}
}
//A接口
interface A
{
}
//B接口
interface B
{
}
//第一种方式,实现两个接口,就是单一类
class X implements A,B
{
}
//第二种方式,使用内部类
class Y implements A
{
B makeB()
{
//使用匿名内部类
return new B()
{
};
}
}
package com.book.chapter10.innerClass;
/**
*
*多层嵌套类中访问外围类的成员
*展示从不同的类里创建多层嵌套的内部类对象的语法。
*.new语法能产生正确的作用域,所以不必在调用构造器时,限定类名
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-28
*
*/
public class MultiNestingAccess
{
public static void main(Stringargs)
{
MNA mna = new MNA();
//创建mna的内部类A
MNA.A a = mna.new A();
//创建a的内部类B,注意调用方式,需要用a.new
MNA.A.B b = a.new B();
b.h();
}
}
class MNA
{
//私有的f方法
private void f()
{
}
//内部类A
class A
{
//A私有的g方法
private void g()
{
}
//A中的又一个内部类
public class B
{
//可以访问外层的g方法,也可访问最外层的f方法
void h()
{
g();
f();
}
}
}
}
package com.book.chapter10.innerClass;
/**
*
*使用内部类的第一个例子
*
*外围类中方法直接使用内部类
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-16
*
*/
public class Parcel
{
//内部类Contents
class Contents
{
private int i = 3;
public int value()
{
return i;
}
}
//内部类Destination
class Destination
{
private String label;
Destination(String whereTo)
{
label = whereTo;
}
String readLabel()
{
return label;
}
}
//这里使用内部类就像使用其他类一样
//在ship方法中使用内部类,与普通类没有什么不同。在这里,实际的区别就是内部类的名字是嵌套在Parcell的
public void ship(String dest)
{
Contents c = new Contents();
Destination d = new Destination(dest);
System.out.println(d.readLabel());
}
public static void main(Stringargs)
{
Parcel p = new Parcel();
p.ship("China");
}
}
package com.book.chapter10.innerClass;
/**
*
*实例初始化的parcel形式
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Parcel10
{
//注意这里参数必须是final的,因为都需要在匿名内部类中使用
public Destination destination(final String dest,final float price)
{
return new Destination()
{
private int cost;
//实例初始化
{
cost = Math.round(price);
//注意这段代码,即if语句不能作为字段初始化的一部分来执行。所以对于匿名类来说,实例初始化的实际效果就是构造器
if(cost > 100)
{
System.out.println("Over Budget");
}
}
private String label = dest;
@Override
public String readLabel()
{
return label;
}
};
}
public static void main(Stringargs)
{
Parcel10 p10 = new Parcel10();
//传100.3是为了测试,匿名内部类中的实例初始化块中的if语句是否执行
p10.destination("renren", 100.3f);
}
}
package com.book.chapter10.innerClass;
/**
*
*测试内部类之嵌套类-static
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-24
*
*/
public class Parcel11
{
//嵌套类,static
private static class ParcelContents implements Contents
{
private int i = 3;
@Override
public int value()
{
return i;
}
}
//嵌套类,static
protected static class ParcelDestination implements Destination
{
private String label;
private ParcelDestination(String whereTo)
{
label = whereTo;
}
@Override
public String readLabel()
{
return label;
}
//嵌套类中可以有静态方法或静属性
public static void f(){}
static int x = 3;
//又一个静态
static class AnotherLevel
{
public static void f()
{
}
static int x = 10;
}
}
public static Destination destination(String s)
{
return new ParcelDestination(s);
}
public static Contents contents()
{
return new ParcelContents();
}
//main中,没有任何的Parcel11对象是必须的。选择使用了选择static成员的普通语法来调用方法。
public static void main(Stringargs)
{
Contents c = contents();
Destination d = destination("SUN");
}
}
package com.book.chapter10.innerClass;
/**
*
*使用内部类的另一个例子
*
*外围类的方法返回一个指向内部类的引用
*
*如果想从外部类的非静态方法之外的任意位置创建某个类的内部对象,那么就必须具体的指明这个对象的类型,
*OuterClassName.InnerClassName
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-16
*
*/
public class Parcel2
{
//内部类Contents
class Contents
{
private int i = 3;
public int value()
{
return i;
}
}
//内部类Destination
class Destination
{
private String label;
Destination(String whereTo)
{
label = whereTo;
}
String readLabel()
{
return label;
}
}
//返回内部类引用的一个方法
public Destination to(String s)
{
return new Destination(s);
}
//返回内部类应用的另一个方法
public Contents contents()
{
return new Contents();
}
public void ship(String dest)
{
Contents c = new Contents();
Destination d = new Destination(dest);
System.out.println(d.readLabel());
}
public static void main(Stringargs)
{
Parcel2 p1 = new Parcel2();
p1.ship("China");
Parcel2 p2 = new Parcel2();
//注意这里的用法:用以指向内部类的用法
Parcel2.Destination d = p2.to("Beijing");
Parcel2.Contents c = p2.contents();
}
}
package com.book.chapter10.innerClass;
/**
*
*.new语法的继续训练
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-21
*
*/
public class Parcel3
{
//内部类Contents
class Contents
{
private int i = 3;
public int value()
{
return i;
}
}
//内部类Destination
class Destination
{
private String label;
public Destination(String whereTo)
{
label = whereTo;
}
public String readLabel()
{
return label;
}
}
public static void main(Stringargs)
{
Parcel3 p3 = new Parcel3();
//.new 语法
Parcel3.Contents c = p3.new Contents();
Parcel3.Destination d = p3.new Destination("cf");
}
}
package com.book.chapter10.innerClass;
/**
*
*局部内部类使用:本例使用的理由是-你实现了某类型的接口,于是可以创建并返回对其的引用。
*方法中的局部内部类是属于方法的一部分,而不是类的一部分。所以在方法之外不能访问。
*当然在方法中定义了内部类,并不意味着一旦该方法执行完毕,该内部类就不可用了。
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-21
*
*/
public class Parcel5
{
public Destination destination(String s)
{
//方法内的局部内部类,挺nx的用法的,注意PDestination是方法的一部分,而不是Parcell5的一部分,方法之外不能访问。
class PDestination implements Destination
{
private String label;
private PDestination(String s)
{
label = s;
}
public String readLabel()
{
return label;
}
}
return new PDestination(s);
}
public static void main(Stringargs)
{
Parcel5 p5 = new Parcel5();
Destination d = p5.destination("dl");
}
}
package com.book.chapter10.innerClass;
/**
*
*在任意的作用域内嵌入内部类
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-22
*
*/
public class Parcel6
{
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");
System.out.println(ts.getSlip());
}
//不能在作用域之外使用局部内部类TrackingSlip,因为不可见,所以cannot be resolved to a type
// TrackingSlip ts2 = new TrackingSlip("slip2");
}
public void track()
{
internalTracking(true);
}
public static void main(Stringargs)
{
Parcel6 parcel6 = new Parcel6();
parcel6.track();
}
}
package com.book.chapter10.innerClass;
/**
*
*匿名内部类使用的第一个demo
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-22
*
*/
public class Parcel7
{
public Contents contents()
{
//匿名内部类,匿名,没有名字,创建一个继承自Contents的匿名类的对象.通过new表达式返回的引用被自动向上转型为对Contents的引用
return new Contents()
{
private int i = 3;
@Override
public int value()
{
return i;
}
};
}
public static void main(Stringargs)
{
Parcel7 p7 = new Parcel7();
p7.contents();
}
}
package com.book.chapter10.innerClass;
/**
*
*{@link Parcel7}中的匿名内部类是本形式的简化形式
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Parcel7b
{
class MyContents implements Contents
{
private int i = 3;
public int value()
{
return i;
}
}
public Contents contents()
{
return new MyContents();
}
public static void main(Stringargs)
{
Parcel7b p7b = new Parcel7b();
Contents c = p7b.contents();
}
}
package com.book.chapter10.innerClass;
/**
*
*匿名内部类传参数
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Parcel8
{
public Wrapping wrapping(int x)
{
//注意看这里的用法,即使Wrapping是一个普通类,但其还是被其导出类当做”公共接口“来使用
return new Wrapping(x)
{
//更要注意,这里用到了Override关键字,说明返回的这个匿名内部类是Wrapping的一个子类
@Override
public int value()
{
return super.value() * 3;
}
};//注:这个分号只是标记表达式的结束,只不过这个表达式正巧包含了内部类而已。并不是用来标识此内部类的结束的。因此,这地方与别的地方使用的分号是一致的。
}
}
//一个具有实现的普通类
class Wrapping
{
private int i;
public Wrapping(int x)
{
i = x;
}
public int value()
{
return i;
}
}
package com.book.chapter10.innerClass;
/**
*
*在匿名类中定义字段时,还能够对其执行初始化操作。如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,
*那么编译器会要求其参数引用是final的。如果你忘了,会得到一个编译时错误消息。
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-23
*
*/
public class Parcel9
{
//注意如果该参数需要在内部类中使用to use,该参数必须是final,因为dest被用在了label的初始化,即给字段赋值
public Destination destination(final String dest)
{
return new Destination()
{
//匿名类中定义了一个字段,并且执行了初始化
private String label = dest;
@Override
public String readLabel()
{
return "";
}
};
}
public static void main(Stringargs)
{
Parcel9 p9 = new Parcel9();
Destination d = p9.destination("final place");
System.out.println(d.readLabel());
}
}
package com.book.chapter10.innerClass;
/**
*
*测试内部类访问外围类成员
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-17
*
*/
public class Sequence
{
//外围对象成员 items
private Object[] items;
private int next = 0;
public Sequence(int size)
{
items = new Object[size];
}
//向items添加
public void add(Object obj)
{
if(next < items.length)
{
items[next++] = obj;
}
}
//私有内部类,顺序的Selector
private class SequenceSelector implements Selector
{
private int i = 0;
//直接访问外围类成员items
@Override
public boolean end()
{
return i == items.length;
}
//直接访问外围类成员items
@Override
public Object current()
{
return items[i];
}
//直接访问外围类成员items
@Override
public void next()
{
if(i < items.length)
{
i++;
}
}
}
public Selector getSelector()
{
return new SequenceSelector();
}
public static void main(Stringargs)
{
Sequence sequence = new Sequence(10);
for(int i = 0;i < 10;i++)
{
sequence.add(Integer.toString(i));
}
//内部类与外围类相关联
Selector selector = sequence.getSelector();
while(!selector.end())
{
System.out.println("Selector.current: " + selector.current() + " ");
selector.next();
}
}
}
//Selector接口,迭代器模式
interface Selector
{
boolean end();
Object current();
void next();
}
package com.book.chapter10.innerClass;
/**
*
*将测试的main方法写在嵌套类中,生成的class为TestBed$Tester.class
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-28
*
*/
public class TestBed
{
public void f()
{
System.out.println("f()");
}
//嵌套的内部类
public static class Tester
{
public static void main(Stringargs)
{
new TestBed().f();
}
}
}
package com.book.chapter10.innerClass;
/**
*
*测试,内部类的向上转型
*可以非常方便的隐藏实现细节,通过将内部类修饰为private或者protected
*
*@author landon
*@since JDK1.6
*@version 1.0 2012-5-21
*
*/
public class TestParcel
{
public static void main(Stringargs)
{
Parcel4 p4 = new Parcel4();
//外部调用的时候,客户端根本无法知道具体的实现细节是什么,因为内部类无法对客户端不可见
Destination d = p4.destination("bj");
Contents c = p4.contents();
//The type Parcell4.PContents is not visible,下面的调用是错误的.因为PContents不可见。
//Parcell4.PContents pc = p4.new PContents();
}
}
//外部接口Contents
interface Contents
{
int value();
}
//外部接口Destination
interface Destination
{
String readLabel();
}
class Parcel4
{
//私有内部类,继承外部接口Contents
private class PContents implements Contents
{
private int i = 3;
public int value()
{
return i;
}
}
//protected内部类,继承外部接口Destination
protected class PDestination implements Destination
{
private String label;
public PDestination(String whereTo)
{
label = whereTo;
}
public String readLabel()
{
return label;
}
}
//隐藏了内部的实现细节
public Destination destination(String s)
{
return new PDestination(s);
}
//隐藏了内部的实现细节
public Contents contents()
{
return new PContents();
}
}
相关推荐
### Java内部类总结 在Java编程语言中,内部类是一个重要的概念,它允许开发者在一个类的内部定义另一个类。这种特性极大地增强了代码的封装性和复用性,同时也为解决特定问题提供了灵活的方法。本文将围绕Java内部...
### JAVA内部类总结 在Java编程语言中,内部类(Inner Classes)是一种非常重要的特性,它允许我们在一个类的内部定义另一个类。这种结构不仅能够提高代码的组织性,还能帮助我们更好地处理类与类之间的关系。根据...
Java 内部类总结 Java 内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的。内部类可为静态,可用 protected 和 private 修饰(而外部类只能使用 public 和缺省的包...
定义在一个类内部的类叫内部类,包含内部类的类称为外部类。内部类可以声明public、protected、private等访问限制,可以声明为abstract的供其他内部类或外部类继承与扩展,或者声明为static、final的,也可以实现...
Java内部类详解 Java内部类是Java语言中的一种特殊类别,它是指定义在另外一个类内部的类。内部类可以访问外部类的所有成员变量和方法,包括私有的变量和方法。内部类可以分为四种:成员内部类、静态嵌套类、方法...
Java 内部类总结 Java 内部类是 Java 语言的一个重要概念,指的是在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的。内部类可为静态,可用 protected 和 private 修饰(而...
Java 中的匿名内部类总结 Java 中的匿名内部类是一种特殊的内部类,它没有名字,因此也称为匿名类。匿名内部类是一种简洁的编程方式,能够简化代码编写,但它也有一些限制和特点。 匿名内部类的定义 匿名内部类是...
总结一下,Java内部类是一种强大的工具,它增强了类的封装性和灵活性。通过内部类,开发者可以更好地组织代码,实现更复杂的逻辑,同时保持良好的代码结构。成员内部类提供了对外部类状态的访问,局部内部类提供局部...
Java内部类总结 Java内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的。内部类可为静态,可用protected和private修饰(而外部类只能使用public和缺省的包访问权限...
Java内部类是Java语言中一个独特且强大的特性,它允许我们在一个类的内部定义另一个类。内部类提供了增强封装的能力,使得内部类可以被隐藏在外部类中,仅对外部类可见,从而增加了代码的隐私性和安全性。同时,内部...
总结,Java内部类是一种强大的工具,能够帮助我们更好地组织代码、实现复杂的逻辑和接口。但使用时也需谨慎,避免过度依赖内部类导致代码难以理解和维护。在实际项目中,应根据具体需求选择合适的设计模式。
Java内部类是Java语言的一个独特特性,它允许一个类被定义在另一个类的内部。这种设计使得代码结构更加紧凑,同时也提供了对封装和抽象的新层次。内部类在J2EE编程中可能用得较少,但在GUI编程中尤其常见,主要用于...
总结来说,Java 内部类提供了一种强大的工具,可以增强代码的封装性和灵活性。成员内部类方便访问外部类的私有成员,方法内部类常用于匿名内部类的创建,而静态内部类则允许我们不依赖外部类实例来创建对象。理解并...
Java匿名内部类是Java语言中一个独特且强大的特性,它允许我们在不需要定义一个单独的类的情况下创建类的实例。这在处理回调、事件监听、单例模式以及其他需要短时间内定义一个简单类的情况时非常有用。本篇文章将...
Java 中的内部类是面向对象编程的一个重要特性,它允许在一个类的定义内部定义另一个类。内部类的主要优点是能够方便地访问外部类的私有成员,提供了更封装的代码组织方式,以及创建特定上下文的类实例。下面将详细...