今天咱们说内部类 设计模式
keywords :inner-class 将一个类的定义放在另外一个类的定义内部 数组
有了她,咱们能够把一些逻辑相关的类组织起来并放到一块儿,并控制位于内部类的可视性。起初咱们彻底会作出内部类是一种代码的隐藏机制的判断,但实际上内部类远非如此,她是如此的优雅,能够与外部类发生关系,进行通讯。 app
inner-class 看上去是使人感到怪异的,但她的特性依然让人着迷,并且你必须花费更多的时间去设计以及实践性的去使用他。然而在大多数时间里面,对inner-class的需求并不是显得那么的明显,可是一旦你掌握并能够灵活的使用她,我相信其中的益处也是显而易见的。那么,咱们还在等什么呢? this
如今,咱们将拥有一个内部类:
public class Parcel1{ spa
class Contents{ 设计
private int i=11; code
public int value(){ orm
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-class的objects时,此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[i];
}
public 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,因此细节的东西得以实现隐藏。