您的位置:首页 > 编程语言 > Java开发

java的inner-class

2013-11-14 00:00 369 查看
摘要: Code From By 《Thinking In Java》

今天我们说内部类

keywords :inner-class 将一个类的定义放在另一个类的定义内部

有了她,我们可以把一些逻辑相关的类组织起来并放到一起,并控制位于内部类的可视性。起初我们完全会做出内部类是一种代码的隐藏机制的判断,但实际上内部类远非如此,她是如此的优雅,可以与外部类发生关系,进行通信。

inner-class 看上去是令人感到怪异的,但她的特性依然让人着迷,而且你必须花费更多的时间去设计以及实践性的去使用他。然而在大多数时间里面,对inner-class的需求并非显得那么的明显,但是一旦你掌握并可以灵活的使用她,我相信其中的益处也是显而易见的。那么,我们还在等什么呢?

现在,我们将拥有一个内部类:
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 readLabel;

}

}

public void ship(String dest){

Contents c = new Contents();

Destination d = new Destination();

System.out.println(d.readLabel());

}

public static void man(String[] args){

Parcel1 p =new Parcel1();

p.ship(“Tasmania”);

}

}//Use this code and into your compiler, see the result .

就这段代码而言,实际上通过嵌套,外部类Parcel1的对象p使用了其内部类Destination 中的readLabel方法 ,但是这样的用法没有什么能够让我们惊呼的。

现在,我们将尝试更为奇妙的东西,她将实现这样一个目的:out-class有一个方法,其将返回一个指向内部类的引用;

public class Parcel2{

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;

}

}

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();

System.out.println(d.readLabel());

}

public static void main(String[] args){

Parcel2 p = new Parcel2();

p.ship(“Tasmania”);

Parcel2 q = new Parcel2();

Parcel2.Contents c = q.contents();

Parcel2.Destination d = q.to(“Borneo”);

}

}//Use this code and into your compiler, see the result.

正如我们所看到的,粗体字表明了需要在一个out-class的非static 方法之外的任意位置使用inner-class中的object的用法。

接下来我们来研究以下inner-class 和out-class是如何发生关系链接

现在,你是否还是这样认为,inner-class只是一种名字隐藏和组织代码的模式。你仍然没有感觉到她的奇妙之处。那么现在请注意下面这句话:当生成一个inner-classobjects时,此object与制造它的enclosing object便发生了关系。这种关系就体现在object可以access enclosing object 中的所有成员(attribute or field ,and functions),而这却不需要任何的代价。

看看这段有趣儿的代码:

interface Selector{

boolean end();

Object current();

void next();

}

public class Sequence{

private Object[] items;

private int next=0;

public Sequence(int size){

items= new Object[size];

}

public void add(Object x){
if(next<items.length){

items[next++] = x;

}

}

private class SequenceSelector implements Selector {

private int i=0;

public boolean end(){
return i==items.length;

}

public Object current() {

return items;

}

public [i]void next()
{
if (i<items.length){

i++;

}

}

public Selector selector(){

return new SequenceSelector();

}

public static void main(String[] args){
Sequence sequence = new Sequence(10);

for(int i =0;i<10;i++){

sequence.add(Integer.toString(i));

}

Selector selector = sequence.selector();

while(!selector.end()){

System.out.println(selector.end() + “ ”);

selector.next();

}

}

}//Use this code and into your compiler, see the result.

Class Sequence 中固定大小的Object数组,是以类的形式包装起来的。只要还有空间即满足 next<items.length ,即可以调用add()方法以实现在序列的末尾处添加新的object。现在我们需要使用Sequence这个类中的对象,那么,不难想象到我们可以使用interface。请注意下面这句话,它有关于“迭代器”的设计模式要获取Sequence中的每个对象,可以使用Selector接口。相应的,我们不难看出,所有实现了Selector接口的类看上去都是实现了这样一些功能的(function):end()方法可以检查序列是否到了末尾,current()方法可以访问当前对象,而next()功能则实现了移到序列的下一个对象。因为Selector是一个接口而非抽象类,所以很灵活的,当类SequenceSelector 实现了Selector接口时,它可以以自己的所喜欢的style去运转。再看看SequenceSelector这个类,他是个Private的类。也正是通过他,Selector接口中所描绘出的功能,才能够得以实现。在入口方法中,我们将Sequence这个包含有一个固定长度的数组的类实例化了,并给它传递了一个整数型的参数。这样,一个定长的数组也就诞生了。接着我们利用对象包装器,向里面添加一些String类型的对象。最后,使用Sequence类的对象sequence的selector方法,得到一个返回值为协变返回类型的对象,并将其赋值给Selector接口的实例化selector。现在你还认为inner-class技术不过如此吗,如果你还这么想,那么再仔细看一下实现了Selector接口的类SequenceSelector中的三个方法,他们都用到了Object,在这里其实是一个引用,其实它并不属于类SequenceSelector,而仅仅是enclosing class 中的一个私有的filed。这样看来inner-class已经拥有了enclosing class中的所有内容。这是多么令人不可思议啊,你可能会这样问,那么这是如何实现的呢?inner-class 会在适当的时候catch一个指向那个enclosing-class的引用。就这样,当你用inner-class的对象access那个enclosing-class的内容的之前,会调用那个引用,实际上那个神秘兮兮“引用先生”在访问enclosing-class的内容。当然,这一切都是托了compiler的福。

关于.this和.new

看到这两个熟悉的keywords,你一定有很多想说的,他们对我们来说是显得那么的熟悉,但同时也常常会令我们十分苦恼。

现在想要引用out-class的object,那么可以这样写

out-classname.this 这样做的好处就是我们可以自动获得一个正确类型的对象,编译器会帮助我们做好审查工作,换回来的当然是运行时的零开销。

看看这个“.this”是如何apply的:

public class DoThis{

void() f(){
System.out.println(“DoThis.f()”);

}

public class Inner{
public DoThis outer(){

return DoThis.this;

}

}

public Inner inner(){

return new Inner();

}

public static void main(String[] args){
DoThis dt = new DoThis();

DoThis.Inner dti = dt.inner();

dti.outer().f();

}

}Use this code and into your compiler ,see the result

现在你明白了,如何生成对外部类对象的引用,那么你也许会问,如果想要让某些小家伙(enclosing-class's object)去创建在它们自己内部的某个inner-class's object ?

接下来我将展示,上面的问题时如何在代码中得以实现的

public class DotNew{

public class inner{

//nothing in this class.

}

public static void main(String[] args){

DotNew dn = new DotNew();

DotNew.Inner dni = dn.new inner();

}

}//Use this code and into your compiler ,see the result.

请记住,如果想要去创建一个inner-class's object,那么应该使用enclosing-class's object 去创建一个inner-class's object ,所以拥有内部来对象的前提是,你必须先创建一个外部类的对象。不过这也有例外,下面看嵌套类,她是一个静态的内部类,她不需要对外部类对象的引用。

public class Parcel3{

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;

}

}

public static void main(String[] args){
Parcel3 p = new Parcel3();

Parcel3.Contents d = p.new Contents();

Parcel3.Destination d = p.new Destination(“Tasmania”)

}

}Use this code and into your compiler ,see the result.

有关inner-class和up-casting

现在我们试着将内部类up-casting 为一个interface,将会发现这个内部类的(其一定是某个接口的实现),能够完全不可见,并且不可用。我们得到的仅仅是指向其parent-class或者interface的reference,所以细节的东西得以实现隐藏。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java Inner-Class