java的inner-class

今天咱們說內部類 設計模式

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-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[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類的對象sequenceselector方法,獲得一個返回值爲協變返回類型的對象,並將其賦值給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-classobject那麼能夠這樣寫

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-classup-casting

如今咱們試着將內部類up-casting 爲一個interface,將會發現這個內部類的(其必定是某個接口的實現),可以徹底不可見,而且不可用。咱們獲得的僅僅是指向其parent-class或者interfacereference,因此細節的東西得以實現隱藏。

相關文章
相關標籤/搜索