1. 程式人生 > >java程式設計思想 第 10 章 內部類

java程式設計思想 第 10 章 內部類

將一個類的定義放在另一類的定義內部,這就是內部類

一、 建立內部類

把內部類的定義置於外圍類的裡面:

//: innerclasses/Parcel1.java
// Creating inner classes.

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
label; } } // Using inner classes looks just like // using any other class, within Parcel1: public void ship(String dest) { Contents c = new Contents(); Destination d = new Destination(dest); System.out.println(d.readLabel()); } public static void main(String[] args) { Parcel1 p = new
Parcel1(); p.ship("Tasmania"); } } /* Output: Tasmania *///:~

ship()方法使用內部類與使用外部類沒有區別。內部類的名稱巢狀在外部類的裡面。

更多的情況是外部類的方法返回一個內部類的引用。
就像下面的to()和content()方法一樣。

//: innerclasses/Parcel2.java
// Returning a reference to an inner 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 = contents(); Destination d = to(dest); System.out.println(d.readLabel()); } public static void main(String[] args) { Parcel2 p = new Parcel2(); p.ship("Tasmania"); Parcel2 q = new Parcel2(); // Defining references to inner classes: Parcel2.Contents c = q.contents(); Parcel2.Destination d = q.to("Borneo"); } } /* Output: Tasmania *///:~

如果想從外部類的非靜態方法之外的任意位置建立某個內部類物件。必須像main()方法一樣,具體指明這個物件的型別:OuterClassName.InnerClassName

練習1:

// innerclasses/Outer1.java
// TIJ4 Chapter Innerclasses, Exercise 1, page 347
/* Write a class named Outer that contains an inner class named Innet. 
* Add a method to Outer that returns an object of type Inner. In main(),
* create and initialize a reference to an Inner.
*/

public class Outer1 {
    class Inner { 
        Inner() { System.out.println("Inner()"); }
    }
    Outer1() { System.out.println("Outer1()"); }
    // make an Inner from within a non-static method of outer class:
    Inner makeInner() {
        return new Inner();
    }
    public static void main(String[] args) {
        Outer1 o = new Outer1();
        Inner i = o.makeInner();
    }
}

#output
Outer1()
Inner()

二、連結到外部類

當生成一個內部類物件時,內部物件對外部類的所有成員具有訪問許可權,沒有任何限制。

//: innerclasses/Sequence.java
// Holds a sequence of Objects.

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.print(selector.current() + " ");
      selector.next();
    }
  }
} /* Output:
0 1 2 3 4 5 6 7 8 9
*///:~

Sequence類內部有一個Object[]陣列,為了訪問該陣列,可以通過內部類SequenceSelector.內部類SequenceSelector用到了外部類的items變數,該變數是一個引用。這個就是迭代器設計模式的一個例子。

內部類自動擁有對外部類所有成員的訪問許可權。這是因為外部類物件建立內部類物件時,內部類物件會祕密擁有一個指向外部類物件的引用,使用外部 類的成員時,內部類物件通過外部類物件的引用來訪問外部類的成員。這個細節由編譯器處理。

對於非static修飾的內部類,只能通過外部類物件的一個引用來建立。
練習2:

// innerclasses/Sequence2.java
// TIJ4 Chapter Innerclasses, Exercise 2, page 350
/* Create a class that holds a String, and has a toString() method that
* displays this String. Add several instances of your new class to a 
* Sequence ojbect, then display them.
*/

class Word {
    private String word;
    public Word(String s) { word = s; }
    public String toString() { return word; }
} 

interface Selector {
    boolean end();
    Object current();
    void next();
}

public class Sequence2 {
    private Object[] items;
    private int next = 0;
    public Sequence2(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) {
        Sequence2 sequence = new Sequence2(10);
        for(int i = 0; i < 10; i++)
            sequence.add(new Word(Integer.toString(i)));
        Selector selector = sequence.selector();
        while(!selector.end()) {
            System.out.print(selector.current() + " ");
            selector.next();
        }
        Word w1 = new Word("Peace");
        Word w2 = new Word("Love");
        Word w3 = new Word("Easter");
        Sequence2 message = new Sequence2(3);
        message.add(w1);
        message.add(w2);
        message.add(w3);
        Selector sel = message.selector();
        while(!sel.end()) {
            System.out.print(sel.current() + " ");
            sel.next();
        }

    }
}

# output

0 1 2 3 4 5 6 7 8 9 Peace Love Easter

練習3:

// innerclasses/Outer3.java
// TIJ4 Chapter Innerclasses, Exercise 3, page 350
/* Modify Exercise 1 so that Outer has a private String field (initialized
* by the constructor), and Inner has a toString() that displays this field.
* Create an object of type Inner and display it.
*/

public class Outer3 {
    private String s;
    class Inner3 { 
        Inner3() { System.out.println("Inner()"); }
        public String toString() { return s; }
    }
    Outer3(String s) { 
        System.out.println("Outer1()");
        this.s = s;
    }
    Inner3 makeInner3() {
        return new Inner3();
    }
    public static void main(String[] args) {
        Outer3 o = new Outer3("Hi is risen!");
        Inner3 i = o.makeInner3();
        System.out.println(i.toString());
    }
}
# output
Outer1()
Inner()
Hi is risen!

三、使用.this和new

如果需要在內部類中獲取外部類物件的引用,使用外部類名緊跟圓點和this即可獲取外部類物件的正確引用。
例如下列:

//: innerclasses/DotThis.java
// Qualifying access to the outer-class object.

public class DotThis {
  void f() { System.out.println("DotThis.f()"); }
  public class Inner {
    public DotThis outer() {
      return DotThis.this;
      // A plain "this" would be Inner's "this"
    }
  }
  public Inner inner() { return new Inner(); }
  public static void main(String[] args) {
    DotThis dt = new DotThis();
    DotThis.Inner dti = dt.inner();
    dti.outer().f();
  }
} /* Output:
DotThis.f()
*///:~

要想建立一個內部類物件,必須在new表示式中提供對其它外部類物件的引用。這需要.new 語法。

//: innerclasses/DotNew.java
// Creating an inner class directly using the .new syntax.

public class DotNew {
  public class Inner {}
  public static void main(String[] args) {
    DotNew dn = new DotNew();
    DotNew.Inner dni = dn.new Inner();
  }
} ///:~

如果想要直接建立內部類物件,不能使用new new Outer.Inner()建立物件,必須使用外部類物件來建立內類物件。

在擁有外部類物件之前,是不能建立內部類物件的。這是因為內部類物件建立時必須繫結到一個外部類物件。如果是巢狀類(靜態內部類)則可以直接建立內部類物件。

//: innerclasses/Parcel3.java
// Using .new to create instances of inner classes.

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();
    // Must use instance of outer class
    // to create an instance of the inner class:
    Parcel3.Contents c = p.new Contents();
    Parcel3.Destination d = p.new Destination("Tasmania");
  }
} ///:~

練習4:

// innerclasses/Sequence4.java
// TIJ4 Chapter Innerclasses, Exercise 4, page 352
/* Add a method to the class Sequence.SequenceSelector that produces the 
* reference to the outer class Sequence.
*/

interface Selector {
    boolean end();
    Object current();
    void next();
}

public class Sequence4 {
    private Object[] items;
    private int next = 0;
    // to test SequenceSelector sequence4() in main():
    public void test() { System.out.println("Sequence4.test()"); }
    public Sequence4(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++; } 
        // method to produce outer class reference:
        public Sequence4 sequence4() { return Sequence4.this; }
    }
    public Selector selector() {
        return new SequenceSelector();
    }
    public static void main(String[] args) {
        Sequence4 sequence = new Sequence4(10);
        for(int i = 0; i < 10; i++)
            sequence.add(Integer.toString(i));
        Selector selector = sequence.selector();
        while(!selector.end()) {
            System.out.print(selector.current() + " ");
            selector.next();
        }
        // cast and test:
        ((SequenceSelector)selector).sequence4().test();    
    }
}

四、內部類和向上轉型

將內部類向上轉型為其父類或實現的介面時,能夠獲得指向內部類父類或介面的引用。隱藏內部類實現的細節。

兩個介面:

//: innerclasses/Contents.java
public interface Contents {
  int value();
} ///:~


//: innerclasses/Destination.java
public interface Destination {
  String readLabel();
} ///:~

Contents和Destination表示客戶端程式設計師可用的介面。(介面所有成員被自動設為public)
當取得了一個指向基類或介面的引用時,甚至無法找出它確切的型別

//: innerclasses/TestParcel.java

class Parcel4 {
  private class PContents implements Contents {
    private int i = 11;
    public int value() { return i; }
  }
  protected class PDestination implements Destination {
    private String label;
    private 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();
  }
}

public class TestParcel {
  public static void main(String[] args) {
    Parcel4 p = new Parcel4();
    Contents c = p.contents();
    Destination d = p.destination("Tasmania");
    // Illegal -- can't access private class:
    //! Parcel4.PContents pc = p.new PContents();
  }
} ///:~

Parcel4有兩個內部類:內部類PCcontents是private ,所以該類只能在Parcel4類中被訪問,其它類無法訪問。PDestination類是Protected,所以它只能被Parcel4以及Parcel4子類、同一個包中的類訪問

練習6:

// innerclasses/Ex6.java
// TIJ4 Chapter Innerclasses, Exercise 6, page 353
/* Create an interface with at least one method, in its own package. Create
* a class in a separate package. Add a protected inner class that 
* implements the interface. In a third package, inherit from your class and
* inside a method, return an object of the protected inner class, upcasting
* to the interface during the return.
*/

/* // in separate package:
* public interface Ex6Interface {
*   String say();
* }
*
* // and in a second package:
* public class Ex6Base {
*   protected class Ex6BaseInner implements Ex6Interface {
*       // need public constructor to create one in Ex6Base child: 
*       public Ex6BaseInner() { }
*       public String say() { return "Hi"; }
*   }
* }
*/ 

import innerclasses.ex6Interface.*;
import innerclasses.ex6Base.*;

public class Ex6 extends Ex6Base {
    Ex6Interface getBaseInner() { 
        return this.new Ex6BaseInner();
    }
    public static void main(String[] args) {
        Ex6 ex = new Ex6();
        System.out.println(ex.getBaseInner().say());
    }   
}

練習7:

// innerclasses/Outer7.java
// TIJ4 Chapter Innerclasses, Exercise 7, page 354
/* Create a class with a private field and a private method. Create an
* inner class with a method that modifies the outer-class field and calls
* the outer class method. In a second outer-class method, create an object
* of the inner class and call its method, then show the effect on the
* outer-class object. 
*/

class Outer7 {
    private int oi = 1;
    private void hi() { System.out.println("Outer hi"); }
    class Inner {
        void modifyOuter() { 
            oi *= 2;
            hi(); 
        }
    }
    public void showOi() { System.out.println(oi); }
    void testInner() {
        Inner in = new Inner();
        in.modifyOuter();
    }
    public static void main(String[] args) {
        Outer7 out = new Outer7();
        out.showOi();
        out.testInner();
        out.showOi();
    }
}

練習8:

// innerclasses/Outer8.java
// TIJ4 Chapter Innerclasses, Exercise 8, page 354
/* Determine whether an outer class has access to the private elements of 
* its inner class. 
*/

class Outer8 {  
    class Inner {
        private int ii1 = 1;
        private int ii2 = 2;
        private void showIi2() { System.out.println(ii2); }
        private void hi() { System.out.println("Inner hi"); }
        }
    // Need to create objects to access private elements of Inner:
    int oi = new Inner().ii1;
    void showOi() { System.out.println(oi); }
    void showIi2() { new Inner().showIi2(); } 
    void outerHi() { new Inner().hi(); }
    public static void main(String[] args) {
        Outer8 out = new Outer8();
        out.showOi();
        out.showIi2();
        out.outerHi();
    }
}

外部類可以訪問內部類的private 元素

五、在方法和作用域內部的內部類
在方法的作用域內建立一個類,該類被稱為區域性內部類。

//: innerclasses/Parcel5.java
// Nesting a class within a method.

public class Parcel5 {
  public Destination destination(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) {
    Parcel5 p = new Parcel5();
    Destination d = p.destination("Tasmania");
    System.out.println(d.readLabel());
  }
} ///:~

#output
Tasmania

PDestination類是destination方法的一部分,destination方法執行完畢後,d 仍持有該區域性內部類物件。
任意作用域內嵌入一個內部類:

//: innerclasses/Parcel6.java
// Nesting a class within a scope.

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");
      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) {
    Parcel6 p = new Parcel6();
    p.track();
  }
} ///:~

該類在定義TrackingingShip的作用域之外,是不可用,除此之外,和普通類沒有什麼不同。
練習9

// innerclasses/Ex9.java
// TIJ4 Chapter Innerclasses, Exercise 9, page 356
/* Create an interface with at least one method, and implement that
* interface by defining an inner class within a method, which returns a
* reference to your interface.
*/

interface Ex9Interface {
    void say(String s); 
}

public class Ex9 {  
    Ex9Interface f() {
        class Inner implements Ex9Interface {
            public void say(String s) {
                System.out.println(s); 
            }
        }
        return new Inner();
    }
    public static void main(String[] args) {
        Ex9 x = new Ex9();
        x.f().say("hi");
    } 
}

練習10

// innerclasses/Ex10.java
// TIJ4 Chapter Innerclasses, Exercise 10, page 356
/* Repeat the previous exercise but define the inner class within a
* scope with scope within a method.
*/

interface Ex10Interface {
    void say(String s); 
}

public class Ex10 { 
    Ex10Interface f(boolean b) {
        if(b) {
            class Inner implements Ex10Interface {
                public void say(String s) {
                    System.out.println(s); 
                }
            }
            return new Inner();
        }
        return null;
    }
    public static void main(String[] args) {
        Ex10 x = new Ex10();
        x.f(true).say("hi");
    } 
}

練習11:

// innerclasses/Ex11.java
// TIJ4 Chapter Innerclasses, Exercise 11, page 356
/* Create a private inner class that implements a public interface.
* Write a method that returns a reference to an instance of the private
* inner class, upcast to the interface. Show that the inner class is 
* completely hidden by trying to downcast to it.
*/

/* public interface Ex11Interface {
*   void say(String s); 
* }
*/

class Test {
    private class Inner implements Ex11Interface {
        public void say(String s) {
            System.out.println(s); 
        }
    }
    Ex11Interface f() {
        return new Inner();
    }
}
public class Ex11 { 
    public static void main(String[] args) {
        Test t = new Test();
        t.f().say("hi");
        // Error: cannot find symbol: class Inner:
        // ((Inner)t.f()).say("hello");
    } 
}

六、匿名內部類

//: innerclasses/Parcel7.java
// Returning an instance of an anonymous inner class.

public class Parcel7 {
  public Contents contents() {
    return new Contents() { // Insert a class definition
      private int i = 11;
      public int value() { return i; }
    }; // Semicolon required in this case
  }
  public static void main(String[] args) {
    Parcel7 p = new Parcel7();
    Contents c = p.contents();
  }
} ///:~

Content是一個介面,建立匿名內部類實現Content介面並在後面緊跟該匿名內部類的定義。
上面是以下建立物件的簡潔方式

//: innerclasses/Parcel7b.java
// Expanded version of Parcel7.java

public class Parcel7b {
  class MyContents implements Contents {
    private int i = 11;
    public int value() { return i; }
  }
  public Contents contents() { return new MyContents(); }
  public static void main(String[] args) {
    Parcel7b p = new Parcel7b();
    Contents c = p.contents();
  }
} ///:~

上面的匿名內部中,使用預設的構造器來生成Contents。如果基類需要有參建構函式呢?

//: innerclasses/Parcel8.java
// Calling the base-class constructor.

public class Parcel8 {
  public Wrapping wrapping(int x) {
    // Base constructor call:
    return new Wrapping(x) { // Pass constructor argument.
      public int value() {
        return super.value() * 47;
      }
    }; // Semicolon required
  }
  public static void main(String[] args) {
    Parcel8 p = new Parcel8();
    Wrapping w = p.wrapping(10);
  }
} ///:~

只需要傳遞引數即可。Wrapping只是一個具有具體實現的普通類,但他仍被當作公共介面來使用

//: innerclasses/Wrapping.java
public class Wrapping {
  private int i;
  public Wrapping(int x) { i = x; }
  public int value() { return i; }
} ///:~

匿名內部類後面的分號是表示表示式的結束。

在匿名內部類中定義欄位時,能夠對其執行初始化操作。

//: innerclasses/Parcel9.java
// An anonymous inner class that performs
// initialization. A briefer version of Parcel5.java.

public class Parcel9 {
  // Argument must be final to use inside
  // anonymous inner class:
  public Destination destination(final String dest) {
    return new Destination() {
      private String label = dest;
      public String readLabel() { return label; }
    };
  }
  public static void main(String[] args) {
    Parcel9 p = new Parcel9();
    Destination d = p.destination("Tasmania");
  }
} ///:~

如果定義一個匿名內部類,並且希望它使用一個在外部定義的物件,那麼編譯器要求其引數引用是final的。

匿名內部類不可能有構造器,但可以通過例項初始化達到構造器效果。

//: innerclasses/AnonymousConstructor.java
// Creating a constructor for an anonymous inner class.
import static net.mindview.util.Print.*;

abstract class Base {
  public Base(int i) {
    print("Base constructor, i = " + i);
  }
  public abstract void f();
}   

public class AnonymousConstructor {
  public static Base getBase(int i) {
    return new Base(i) {
      { print("Inside instance initializer"); }
      public void f() {
        print("In anonymous f()");
      }
    };
  }
  public static void main(String[] args) {
    Base base = getBase(47);
    base.f();
  }
} /* Output:
Base constructor, i = 47
Inside instance initializer
In anonymous f()
*///:~

在上面例項中,不要求變數i為final的,因為它被傳遞給匿名內部類的基類構造器使用,而不是被匿名內部類直接使用。

destination方法的引數必須為final的。

//: innerclasses/Parcel10.java
// Using "instance initialization" to perform
// construction on an anonymous inner class.

public class Parcel10 {
  public Destination
  destination(final String dest, final float price) {
    return new Destination() {
      private int cost;
      // Instance initialization for each object:
      {
        cost = Math.round(price);
        if(cost > 100)
          System.out.println("Over budget!");
      }
      private String label = dest;
      public String readLabel() { return label; }
    };
  } 
  public static void main(String[] args) {
    Parcel10 p = new Parcel10();
    Destination d = p.destination("Tasmania", 101.395F);
  }
} /* Output:
Over budget!
*///:~

匿名內部類即可擴充套件類,也可擴充套件介面,但不能兩者兼備。
練習14:

// innerclasses/HorrorShow14.java
// TIJ4 Chapter Innerclasses, Exercise 14, page361
/* Modify interfaces/HorrorShow.java to implement DangerousMonster and
* Vampire using anonymous classes.
*/
import static org.greggordon.tools.Print.*;

interface Monster {
    void menace();
}   

interface DangerousMonster extends Monster {
    void destroy();
}   

interface Lethal {
    void kill();
}

class DragonZilla implements DangerousMonster {
    public void menace() {}
    public void destroy() {}
}

interface Vampire extends DangerousMonster, Lethal {
    void drinkBlood();
}

class VeryBadVampire implements Vampire {
    public void menace() {}
    public void destroy() {}
    public void kill() {}
    public void drinkBlood() {} 
}

public class HorrorShow14 {
    static void u(Monster b) { b.menace(); }
    static void v(DangerousMonster d) {
        d.menace();
        d.destroy();
    }
    static void w(Lethal l) { l.kill(); }
    public DangerousMonster monsterMaker() {
        return new DangerousMonster() {
            public void menace() { println("DangerousMonster Menace"); }
            public void destroy() { println("DangerousMonster Destroy"); }
        };
    }
    public Vampire vampireMaker() {
        return new Vampire() {
            public void menace() { println("Vampire Menace"); }
            public void destroy() { println("Vampire Destroy"); }
            public void kill() { println("Vampire Kill"); }
            public void drinkBlood() { println("Vampire DrinkBlood"); }
        };
    }       
    public static void main(String[] args) {
        HorrorShow14 show = new HorrorShow14();
        show.u(show.monsterMaker());
        show.v(show.monsterMaker());
        show.u(show.vampireMaker());
        show.v(show.vampireMaker());
        show.w(show.vampireMaker());
    }
}

練習15:

// innerclasses/Ex15.java
// TIJ4 Chapter Innerclasses, Exercise 15, page361
/* Create a class with a non-default constructor and no default constructor.
* Create a second class that has a method that returns a reference to an
* object of the first class. Create the object that you return by making an
* anonymous inner class that inherits from the first class. 
*/

class One {
    private String s;
    One(String s) { this.s = s; } 
    public String showS() { return s; }
}

public class Ex15 {
    public One makeOne(String s) {
        return new One(s) { };
    }
    public static void main(String[] args) {
        Ex15 x = new Ex15();
        System.out.println(x.makeOne("hi").showS());
    }
}
#output

hi

6.1 再訪工程方法

使用匿名內部類,interfaces/Factories.java.

//: innerclasses/Factories.java
import static net.mindview.util.Print.*;

interface Service {
  void method1();
  void method2();
}

interface ServiceFactory {
  Service getService();
}   

class Implementation1 implements Service {
  private Implementation1() {}
  public void method1() {print("Implementation1 method1");}
  public void method2() {print("Implementation1 method2");}
  public static ServiceFactory factory =
    new ServiceFactory() {
      public Service getService() {
        return new Implementation1();
      }
    };
}   

class Implementation2 implements Service {
  private Implementation2() {}
  public void method1() {print("Implementation2 method1");}
  public void method2() {print("Implementation2 method2");}
  public static ServiceFactory factory =
    new ServiceFactory() {
      public Service getService() {
        return new Implementation2();
      }
    };
}   

public class Factories {
  public static void serviceConsumer(ServiceFactory fact) {
    Service s = fact.getService();
    s.method1();
    s.method2();
  }
  public static void main(String[] args) {
    serviceConsumer(Implementation1.factory);
    // Implementations are completely interchangeable:
    serviceConsumer(Implementation2.factory);
  }
} /* Output:
Implementation1 method1
Implementation1 method2
Implementation2 method1
Implementation2 method2
*///:~

同理

//: innerclasses/Games.java
// Using anonymous inner classes with the Game framework.
import static net.mindview.util.Print.*;


            
           

相關推薦

java程式設計思想 10 部類

將一個類的定義放在另一類的定義內部,這就是內部類 一、 建立內部類 把內部類的定義置於外圍類的裡面: //: innerclasses/Parcel1.java // Creating inner classes. public class Pa

java程式設計思想——(部類)》

內部類 可以將一個類的定義放在另一個類的定義內部,這就是內部類。 10.1 建立內部類 把類的定義置於外圍類的裡面。 /** * 建立內部類 * @author Administrator */ public class Parcel1 { class Co

Java程式設計思想10 部類

書中原始碼:https://github.com/yangxian1229/ThinkingInJava_SourceCode 可以將一個類的定義放在另一個類的定義內部,這就是內部類。 內部類與組合是完全不同的概念。 10.1 建立內部類 把類的定義置於外圍類的裡面。更典型的情況是,

Java程式設計思想閱讀筆記(10部類

內部類 內部類是指在一個外部類的內部再定義一個類。內部類作為外部類的一個成員,並且依附於外部類而存在的 可以將一個類的定義放在另一個類定義內部,這就是內部類 內部類自動擁有對包裹它的基類所有成員的訪問許可權 內部類可為靜態,可用protected和priva

JAVA-初步認識--部類-局部內部類

png 方法 image cnblogs -s 只有一個 外部類 理解 輸出 一. 繼續將之前的例子深化一下。現在要講述的是內部類除了放置在成員上,還能放置在局部上。換句話說,就是哪都能放。 這裏局部位置是指哪兒? 繼續將程序補全,截圖如下: 上面的截圖其實交代了內部

JAVA程式設計思想-複用類

1.一個物件被轉換成string時,會呼叫物件的toSting方法 public class demo7 { private water w=new water(); private String s="string"; public static void main(Strin

java程式設計思想——十三(字串)》

字串## 13.1 不可變String## string物件是不可變。String類中每一個看起來會修改String值得方法,實際上都建立了一個新的String物件。 public class Immutable {; public static String upcas

關於Java程式設計思想中 net.jar的匯入

首先右擊你需要匯入net.jar的Eclipse專案,選擇      “構建路徑”-   -“配置構建路徑”  。點選    “庫”   選項卡,單擊右邊的“新增外部JAR”按鈕,然後找到你的 net

Java程式設計思想複用類練習題解答

練習題解答 練習1 練習2 練習3 練習4 練習5 練習6 練習7 練習8 練習9 練習10 練習11 練習12 練習13 練習14 練習15

Java程式設計思想訪問許可權控制練習題解答(待更新完整.......)

練習解答 練習1 練習2 練習3 練習1 先在另一個包建立程式碼,命名為ch6Ex1.java package ch5; public class ch6Ex1 { public ch6Ex1()

Java程式設計思想初始化與清理練習題解答

目錄 1、構造器 練習1 練習2 3、方法過載 練習3 練習4 練習5 練習6 練習7 練習8 練習9 練習10 練習14 練習16

Java 程式設計思想筆記

                                                第三章操作符 一邊做筆記一邊看書,打程式碼更好 第六章靜態匯入是什麼? 3.1 以前我就一直覺得 System 的輸出語句太長了,作者在這裡為我完美的解決了問題,利用靜態匯入這

Java 程式設計思想筆記

    第四章執行控制流程     程式在執行過程中控制他的世界,利用執行控制語句。     Java 使用了 C語言中的所有流程控制語句,Java中設計的關鍵字 if-else while do-while for return break 以及選擇語句 switch。

Java 程式設計思想

                                                                       第五章初始化與清理     初始化與清理是設計安全的兩個問題,C語言中如果使用者不知如何初始化庫的構建,另外資源的佔用,忘記了釋放導

Java程式設計思想 :多型

OOP語言中,多型是封裝、繼承之後的第三種基本特徵。 封裝:通過合併特徵和行為來建立新的資料型別,“實現隱藏”通過細節“私有化”把介面和實現分離 繼承:以複用介面方式從已有型別用extends關鍵字建立新型別,並允許向上轉型 多型:消除型別之間的耦合關係(分離做什麼和怎麼做),基

Java程式設計思想 :複用類

1. 組合用法 程式碼複用是所有語言中都具有的一種特性,我們不必編寫功能相同或相似的程式碼,只需要將原有的程式碼直接拿來或者是在原有程式碼的基礎上進行改動即可。改動的方式有兩種,一種是組合的方式,另一種是繼承的方式。組合方式的使用很常見,前邊的例子也用到過,就是比如說我們新建了一個類,在

Java程式設計思想 :訪問許可權控制

一個優秀的程式設計師是通過不斷的重構程式碼讓自己的程式變得更加易用、可讀和完善的。在重構修改的過程中,如果是一個類庫編寫人員,那麼怎麼樣保證自己修改的部分不會影響到客戶端編寫人員(即使用這個類庫的程式設計師)呢?同時也要避免他們對自己類庫內部的程式進行改動。Java中提供了訪問許可權控制的概

Java程式設計思想 :初始化與清理

1. 用構造器初始化 Java中通過提供構造器,確保每個類的物件都可以得到初始化,構造器的形式為: className(){ //--- } 可以看見程式在初始化物件的時候自動執行了構造方法。 如果類中只有唯一的一個帶引數的構造器,那麼預設的無參構造器將不可用。

Java程式設計思想 十三:字串

1.不可變String String物件是不可變的,每一個看似修改了String值的方法,實際上都是建立了一個全新的String物件。 public class Immutable { public static String upCase(String s){ return

Java程式設計思想習題

練習一:驗證未被初始化的引用被初始化成了null package thinking.java.chapter05; public class Demo01 { public static void main(String[] args) { class Perso