zoukankan      html  css  js  c++  java
  • 第十章内部类

    第十章 内部类

    可以将一个类的定义放在另一个类的定义内部,这就是内部类

    允许你把一些逻辑相关的类组织在一起

    10.1 创建内部类

    把类的定义置于外围类的里面

    外部类有一个方法,该方法返回指向内部类的引用

    任意位置创建某个内部类对象

    OuterClassName.InnerClassName

    public Destination to(String s){
    	return new Destination
    }
    

    练习1

     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 No1Outer {
        class Inner {
            Inner() { System.out.println("Inner()"); }
        }
        No1Outer() { 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) {
            No1Outer o = new No1Outer();
            Inner i = o.makeInner();
        }
    }
    ==========================================================
    Outer1()
    Inner()
    

    10.2 连接到外部类

    内部类似乎只是一种名字隐藏和组织代码模式。当生成一个内部类对象, 此对象与制造它的外围对象就有了一种联系。它能访问外围对象的所有成员,而不需要特殊条件,内部类还拥有其外围类的所有元素的访问权。

    这是怎么做到的呢?

    ​ 当某个外围类的对象创建了一个内部类对象时,此内部类必定会秘密地捕获一个指向那个外围类对象地引用。然后在你访问此外围类地成员时,就是用那个引用来选择外围类的成员。 编译器会帮你处理细节

    ​ 内部类的对象只能与其外围类的对象相关联的情况下才能被创建(就想你应该看到的,在内部类非static类时)。构建内部类对象时,需要一个指向其外围类对象的引用,如果编译器访问不到这个引用就会报错。不过绝大多数这都无需程序员操心。

    练习2

    /* 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 No2Sequence {
        private Object[] items;
        private int next = 0;
        public No2Sequence(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) {
            No2Sequence sequence = new No2Sequence(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");
            No2Sequence message = new No2Sequence(3);
            message.add(w1);
            message.add(w2);
            message.add(w3);
            Selector sel = message.selector();
            while(!sel.end()) {
                System.out.print(sel.current() + " ");
                sel.next();
            }
    
        }
    }
    ==============================================================
    0 1 2 3 4 5 6 7 8 9 Peace Love Easter
    

    练习3

    /* 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.
    
    package 第十章内部类;
    
    public class No3Innter {
        private String s;
        class Inner3 {
            Inner3() { System.out.println("Inner()"); }
            public String toString() { return s; }
        }
        No3Innter(String s) {
            System.out.println("Outer1()");
            this.s = s;
        }
        Inner3 makeInner3() {
            return new Inner3();
        }
        public static void main(String[] args) {
            No3Innter o = new No3Innter("Hi is risen!");
            Inner3 i = o.makeInner3();
            System.out.println(i.toString());
        }
    }
    ==========================================================================
    Outer1()
    Inner()
    Hi is risen! 
    

    10.3 使用.this 与 .new

    .this

    如果你需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟 圆点和this。这样产生的自动引用具有正确的类型,这一点在编译器就被知晓并受到检查。因此没有任何运行时开销。

    .new

    如果你想要告诉其他对象,去创建某个内部类的对象。.new 表达式中提供对其他外部对象的引用。

    在拥有外部类对象之前是不可能创建内部类对象的,这是因为内部类对象会暗暗的连接到创建它的外部类对象上,如果你创建的是 ** 嵌套类静态内部类),那么它不需要对外部类对象的引用**

    练习4

    /* Add a method to the class Sequence.SequenceSelector that produces the 
    * reference to the outer class Sequence.
    
    package 第十章内部类;
    public class No4Sequence {
        private Object[] items;
        private int next = 0;
        // to test SequenceSelector sequence4() in main():
        public void test() { System.out.println("Sequence4.test()"); }
        public No4Sequence(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 No4Sequence sequence4() { return No4Sequence.this; }//内部类引用外部类对象
        }
        public Selector selector() {
            return new SequenceSelector();
        }
        public static void main(String[] args) {
            No4Sequence sequence = new No4Sequence(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();
        }
    }
    ====================================================================
    0 1 2 3 4 5 6 7 8 9 Sequence4.test()
    

    练习5

    /* Create a class with an inner class. In a separate class, make an
     * instance of the inner class.
     */
    
    class Outer {
        class Inner {
            Inner() { System.out.println("Outer.Inner()"); }
        }
    }
    
    
    public class No6OtherOuter {
        public static void main(String[] args) {
            // must first create outer class object:
            Outer o = new Outer();
            // then create inner class object:
            Outer.Inner oi = o.new Inner();
        }
    }
    ==============================================================
    0 1 2 3 4 5 6 7 8 9 Sequence4.test()
    

    10.4 内部类与向上转型

    当内部类向上转型为基类,尤其是转型为一个接口的时候,内部类就有了用武之地。

    /* 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());
    	}	
    =========================================================
        hi    
    

    练习7

    /* 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 No7Outer {
        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) {
            No7Outer out = new No7Outer();
            out.showOi();
            out.testInner();
            out.showOi();
        }
    }
    =============================================================
    1
    Outer hi
    2
    

    练习8

     /*Determine whether an outer class has access to the private elements of 
    * its inner class. */
    class No8Outer {
        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) { 
            No8Outer out = new No8Outer();
            out.showOi();
            out.showIi2();
            out.outerHi();
        }
    }
    =====================================================================
    1
    2
    Inner hi
    

    10.5 在方法和作用域内的内部类

    内部类的语法覆盖了大量其他的更加难以理解的技术。例如:可以在一个方法或者任意作用域内定义内部类。两个原因

    • 实现了某类型的接口,于是可以创建并返回对其的引用
    • 解决一个复杂问题,创建一个类来辅助你的解决方案,但是又不希望这个类是公共可用的

    定义在域中的内部类 只能在类中使用

    练习9

    /* 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 No9Ex {
        Ex9Interface f() {
            class Inner implements Ex9Interface {
                public void say(String s) {
                    System.out.println(s);
                }
            }
            return new Inner();
        }
        public static void main(String[] args) {
            No9Ex x = new No9Ex();
            x.f().say("hi");
        }
    }
    =========================================================
    hi
    

    练习11

    /* 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");
    	} 
    }
    ==========================================================
        hi
    

    练习11

    /* 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");
    	} 
    }
    ================================================
        hi
    

    10.6 匿名内部类

    • 方法的返回值的生成与表示这个的类的定义结合在一起。这个类是匿名的,它没有名字。
    • 在匿名中定义字段时,还能对其执行初始化操作
    • 如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是final的。
    • 通过实例初始化,能够达到为匿名内部类创建一个构造器的效果。
    /* Repeat Exercise 7 using an anonymous inner class.
     * (Exercise 7: 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.)
     */
    
    interface Inner12 {
        void modifyOuter();
    }
    
    public class No12Outer {
        private int oi = 1;
        private void hi() { System.out.println("Outer hi"); }
        public Inner12 inner() {
            return new Inner12() {
                public void modifyOuter() {
                    oi *= 2;
                    hi();
                }
            };
        }
        public void showOi() { System.out.println(oi); }
        public static void main(String[] args) {
            No12Outer out = new No12Outer();
            out.showOi();
            out.inner().modifyOuter();
            out.showOi();
        }
    }
    ====================================================================
    1
    Outer hi
    2
    

    练习13

    /* Repeat Exercise 9 using an anonymous inner class.
    * (Exercise 9: 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 Ex13Interface {
    	String say(String s); 
    }
    
    public class Outer13 {	
    	Ex13Interface f() {
    		return new Ex13Interface() {
    			public String say(String s) { return s; }
    		};
    	} 
    	public static void main(String[] args) {
    		Outer13 o = new Outer13();
    		System.out.println(o.f().say("Hi"));
    	}
    }
    ============================================================
    hi
    

    练习14

    /* Modify interfaces/HorrorShow.java to implement DangerousMonster and
     * Vampire using anonymous classes.
     */
    
    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 No14HorrorShow {
        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() {
                    System.out.println("DangerousMonster Menace"); }
                public void destroy() {
                    System.out.println("DangerousMonster Destroy"); }
            };
        }
        public Vampire vampireMaker() {
            return new Vampire() {
                public void menace() {
                    System.out.println("Vampire Menace"); }
                public void destroy() {
                    System.out.println("Vampire Destroy"); }
                public void kill() {
                    System.out.println("Vampire Kill"); }
                public void drinkBlood() {
                    System.out.println  ("Vampire DrinkBlood"); }
            };
        }
        public static void main(String[] args) {
            No14HorrorShow show = new No14HorrorShow();
            show.u(show.monsterMaker());
            show.v(show.monsterMaker());
            show.u(show.vampireMaker());
            show.v(show.vampireMaker());
            show.w(show.vampireMaker());
        }
    }
    ======================================================================
    DangerousMonster Menace
    DangerousMonster Menace
    DangerousMonster Destroy
    Vampire Menace
    Vampire Menace
    Vampire Destroy
    Vampire Kill
    

    练习15

     /*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 No15Ex {
        public One makeOne(String s) {
            return new One(s) { };
        }
        public static void main(String[] args) {
            No15Ex x = new No15Ex();
            System.out.println(x.makeOne("hi").showS());
        }
    }
    

    10.6.1 在访工厂方法

    练习16

    /* Modify the solution to Exercise 18 from the Interfaces chapter to use
     * anonymous inner classes.
     * (Exercise 18, Interface: Create a Cycle interface, with implementations
     * Unicycle, Bicycle and Tricycle. Create factories for each type of Cycle,
     * and code that uses these factories.
     */
    
    interface Cycle {
        void ride();
    }
    
    interface CycleFactory {
        Cycle getCycle();
    }
    
    class Unicycle implements Cycle {
        private Unicycle() {
            System.out.println("Unicycle()"); }
        public void ride() {
            System.out.println("Ride Unicycle"); }
        public static CycleFactory factory =
                new CycleFactory() {
                    public Cycle getCycle() { return new Unicycle(); }
                };
    }
    
    class Bicycle implements Cycle {
        private Bicycle() {
            System.out.println("Bicycle()"); }
        public void ride() {
            System.out.println("Ride Bicycle"); }
        public static CycleFactory factory =
                new CycleFactory() {
                    public Cycle getCycle() { return new Bicycle(); }
                };
    }
    
    class Tricycle implements Cycle {
        private Tricycle() {
            System.out.println("Tricycle()"); }
        public void ride() {
            System.out.println("Ride Tricycle"); }
        public static CycleFactory factory =
                new CycleFactory() {
                    public Cycle getCycle() { return new Tricycle(); }
                };
    }
    
    public class No16Cycle {
        public static void rideCycle(CycleFactory factory) {
            Cycle c = factory.getCycle();//向上转型
            c.ride();//多态
        }
        public static void main(String [] args) {
            rideCycle(Unicycle.factory);
            rideCycle(Bicycle.factory);
            rideCycle(Tricycle.factory);
        }
    }
    =========================================================================Unicycle()
    Bicycle()
    Tricycle()
    

    练习17

    /* Modify the solution to Exercise 19 from the Interfaces chapter to use
     * anonymous inner classes.
     * (Exercise 19, Interfaces: Create a framework using Factory Methods
     * that performs both coin tossing and dice tossing.
     */
    import java.util.*;
    
    interface Games {
        void play();
    }
    
    interface GamesFactory {
        Games getGames();
    }
    
    class CoinToss implements Games {
        Random rand = new Random();
        public void play() {
            System.out.print("Toss Coin: ");
            switch(rand.nextInt(2)) {
                case 0 :
                    System.out.println("Heads"); return;
                case 1 :
                    System.out.println("Tails"); return;
                default:
                    System.out.println("OnEdge"); return;
            }
        }
        public static GamesFactory factory =
                new GamesFactory() {
                    public Games getGames() { return new CoinToss(); }
                };
    }
    
    class DiceThrow implements Games {
        Random rand = new Random();
        public void play() {
            System.out.println("Throw Dice: " + (rand.nextInt(6) + 1));
        }
        public static GamesFactory factory =
                new GamesFactory() {
                    public Games getGames() { return new DiceThrow(); }
                };
    }
    
    public class No17Game {
        public static void playGame(GamesFactory factory) {
            Games g = factory.getGames();
            g.play();
        }
        public static void main(String [] args) {
            playGame(CoinToss.factory);
            playGame(DiceThrow.factory);
        }
    }
    =======================================================================
    Toss Coin: Heads
    Throw Dice: 1
    

    10.7 嵌套类

    如果不需要内部类对象和外围类对象之间有联系,那么可以将内部类声明为 static。这通常称为 嵌套类

    普通的内部类对象隐式地保存了一个引用,指向创建它的外围类对象。当内部类是 static时,就不是这样了

    嵌套意味着:

    • 要创建嵌套类的对象,并不需要外围类对象
    • 不能从嵌套类的 对象中访问非静态地外围类对象

    普通内部类 的字段和方法 只能放在类的外部层次上,这些普通的内部类不能有 static数据和static字段,也不能包含嵌套类,但是嵌套类可以包含所有这些东西

    联系18

    /* Create a class containing a nested class. In main(), create an instance of
    * the nested class.
    */
    public class No18Ex {
        No18Ex() { System.out.println("Ex18()"); }
        public static class Ex18Nest1 {
            Ex18Nest1() { System.out.println("Ex18Nest1()"); }
        }
        private static class Ex18Nest2 {
            Ex18Nest2() { System.out.println("Ex18Nest2()"); }
        }
        public static void main(String[] args) {
            Ex18Nest1 en1 = new Ex18Nest1();
            Ex18Nest2 en2 = new Ex18Nest2();
        }
    }
    ================================================================
    Ex18Nest1()
    Ex18Nest2()
    

    练习19

    /* Create a class containing an inner class that itself contains an inner
     * class. Repeat this using nested classes. Note the names of the .class files
     * produced by the compiler.
     */
    
    public class No19Ex {
        No19Ex() { System.out.println("Ex19()"); }
        private class Ex19Inner {
            Ex19Inner() { System.out.println("Ex19Inner()"); }
            private class Ex19InnerInner {
                Ex19InnerInner() {
                    System.out.println("Ex19InnerInner()");
                }
            }
        }
        private static class Ex19Nested {
            Ex19Nested() { System.out.println("Ex19Nested()"); }
            private static class Ex19NestedNested {
                Ex19NestedNested() {
                    System.out.println("Ex19NestedNested()");
                }
            }
        }
        public static void main(String[] args) {
            Ex19Nested en = new Ex19Nested();
            Ex19Nested.Ex19NestedNested enn = new Ex19Nested.Ex19NestedNested();
            No19Ex e19 = new No19Ex();
            No19Ex.Ex19Inner ei = e19.new Ex19Inner();
            No19Ex.Ex19Inner.Ex19InnerInner eii = ei.new Ex19InnerInner();
        }
    }
    
    /* compiler produces:
     * Ex19$Ex19Inner$Ex19InnerInner.class
     * Ex19$Ex19Inner.class
     * Ex19$Ex19Nested$Ex19NestedNested.class
     * Ex19$Ex19Nested.class
     * Ex19.class
     */
     ==========================================================================
     Ex19Nested()
    Ex19NestedNested()
    Ex19()
    Ex19Inner()
    Ex19InnerInner()
    

    10.7.1 接口内部类

    不能再接口内放置任何代码,但嵌套类可以作为接口的一部分。放在接口中的任何类都是自动 public 和 static 的,因为内部类是 static的 所以内部类为嵌套类。 只是将嵌套类置于接口的命名空间内:这并不违反接口规则,甚至可以在内部类中实现其外接口。

    可以使用嵌套类来放置 测试 代码

    练习20

    /* Create an interface containing a nested class. Implement this interface and 
    * create an instance of the nested class.
    */
    interface In {
        class Nested {
            Nested() { System.out.println("Nested()"); }
            public void hi() { System.out.println("hi"); }
        }
    }
    
    public class No20 implements In {
        public static void main(String[] args) {
            In.Nested in = new In.Nested();
            in.hi();
        }
    }
    ===================================================================
    Nested()
    hi
    

    练习21

    /* Create an interface that contains a nested class that has a static method that
    * calls the methods of your interface and displays the results. Implement your
    * interface and pass an instance of your implementation to the method. 
    */
    
    interface In {
    	String f();
    	String g(); 
    	class Nested {
    		static void testIn(In i) { 
    			System.out.println(i.f() + i.g());
    		}		
    	}		
    }
    
    public class Ex21 implements In {
    	public String f() { return "hello "; }
    	public String g() { return "friend"; }
    	public static void main(String[] args) {
    		Ex21 x = new Ex21();
    		In.Nested.testIn(x);						
    	}
    }
    ==================================================================
        hello friend
    

    10.7.3 从多层嵌套类中访问外部类的成员

    一个内部类被嵌套多少层不重要--他能透明的访问所有他嵌入的外围类的所有成员,即使是private

    10.8 为什么需要内部类

    内部类继承来自某个类或实现某个接口,内部类的代码操作创建它的外围类对象。所以可以认为内部类提供了某种进入其外围类的窗口。

    内部类实现接口和外围类实现接口的区别:

    • 外围类不能总是享用外围类带来的方便,有时需要用到接口的实现
    • 内部类都能独立地继承一个(接口的)实现,所以无论外围类是否继承了某个(接口的)实现,对于内部类都没有影响。
    • 内部类允许继承多个非接口类型(类或抽象类)

    一个类实现两个接口,如果没有说指定用那种方式实现,他们没有什么区别,但是要是要求继承的是抽象类或者具体类,只有内部类才能实现多重继承。

    • 内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立
    • 在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类
    • 创建外围类对象的时刻并不依赖于内部类对象的创建
    • 内部类并没有令人迷惑的is a 关系,他就一个独立的实体

    练习23

    /* Create an interface U with three methods. Create a class A with a method that
     * produces a reference to a U by building an anonymous inner class. Create a second
     * class B that contains an array of U. B should have one method that accepts and
     * stores a reference to U in the array, a second method that sets a reference in
     * the array (specified by the method argument) to null, and a third method that
     * moves through the array and calls the methods in U. In main, create a group of A
     * objects and a single B. Fill the B with U references produced by the A objects.
     * Use the B to call back into all the A objects. Remove some of the U references
     * from the B.
     */
    
    interface U {
        void f();
        void g();
        String toString();
    }
    
    class A {
        U buildU() {
            return new U() {
                public void f() { System.out.println("f()"); }
                public void g() { System.out.println("g()"); }
                public String toString() { return "I'm a U"; }
            };
        }
    }
    
    class B {
        private U[] us;
        B(int i) {
            us = new U[i];
        }
        void addU(U u, int i) {
            us[i] = u;
        }
        void eraseU(int i) {
            us[i] = null;
        }
        void testUs() {
            for(U u : us) {
                u.f();
                u.g();
                u.toString();
            }
        }
        void showUs() {
            for(U u : us) {
                if(u != null) System.out.println(u.toString());
                else System.out.println("I'm null");
            }
        }
    }
    
    public class No23Ex {
        public static void main(String[] args) {
            A a0 = new A();
            A a1 = new A();
            A a2 = new A();
            B b = new B(3);
            b.addU(a0.buildU(), 0);
            b.addU(a1.buildU(), 1);
            b.addU(a2.buildU(), 2);
            b.showUs();
            b.testUs();
            b.eraseU(0);
            b.eraseU(1);
            b.eraseU(2);
            b.showUs();
        }
    }
    ===============================================================================
    I'm a U
    I'm a U
    I'm a U
    f()
    g()
    f()
    g()
    f()
    g()
    I'm null
    I'm null
    I'm null
    

    10.8.1 闭包与回调

    闭包(closure)是一个可调用对象,它记录了一些信息,这些信息来自于创建它的作用域。

    内部类是面向对象的闭包,不仅包含外部类对象(创建内部类作用域)的信息,还自动拥有一个指向此外围类对象的引用。

    回调 (callvack) 通过回调,对象可以携带一些信息,这些信息允许它在稍后再某个时刻调用初始化的对象。

    10.8.2 内部类与控制框架

    程序设计的关键所在:使变化的事物与不变的事物相互分离

    这正是内部类做的:

    • 控制框架的完整实现是由单个的类创建的,从而实现的细节被封装了起来。内部类用来表示解决问题所必须的各种不同的action
    • 内部类能够很容易地访问外围类地任意成员,所以可以避免这种现实变得笨拙。如果没有这种能力,代码将变得令人讨厌,以至于你肯定会选择别的方法。

    使用内部类 可以再单一地类里面产生对同一个基类Event地多种导出版本。

    练习24

    package 第十章内部类;
    
    import java.util.*;
    abstract class Event {
       private long eventTime;
       protected final long delayTime;
       public Event(long delayTime) {
          this.delayTime = delayTime;
          start();
       }
       public void start() { // Allows restarting
       }
       public boolean ready() {
          return System.nanoTime() >= eventTime;
       }
       public abstract void action();
    }
    
     class Controller {
        // A class from java.util to hold Event objects:
        private List<Event> eventList = new ArrayList<Event>();
    
        public void addEvent(Event c) {
            eventList.add(c);
        }
    
        public void run() {
            while (eventList.size() > 0)
                // Make a copy so you're not modifying the list
                // while you're selecting the elements in it:
                for (Event e : new ArrayList<Event>(eventList))
                    if (e.ready()) {
                        System.out.println(e);
                        e.action();
                        eventList.remove(e);
                    }
        }
    }
    class GreenhouseControls24 extends Controller {
        private boolean fan = false;
        public class FanOn extends Event {
            public FanOn(long delayTime) { super(delayTime); }
            public void action() {
                // Put hardware control code here to
                // physically turn on the fan.
                fan = true;
            }
            public String toString() { return "Fan is on"; }
        }
        public class FanOff extends Event {
            public FanOff(long delayTime) { super(delayTime); }
            public void action() {
                // Put hardware control here to
                // physically turn off the fan.
                fan = false;
            }
            public String toString() { return "Fan is off"; }
        }
        private boolean light = false;
        public class LightOn extends Event {
            public LightOn(long delayTime) { super(delayTime); }
            public void action() {
                // Put hardware control code here to
                // physically turn on the light.
                light = true;
            }
            public String toString() { return "Light is on"; }
        }
        public class LightOff extends Event {
            public LightOff(long delayTime) { super(delayTime); }
            public void action() {
                // Put hardware control here to
                // physically turn off the light.
                light = false;
            }
            public String toString() { return "Light is off"; }
        }
        private boolean water = false;
        public class WaterOn extends Event {
            public WaterOn(long delayTime) { super(delayTime); }
            public void action() {
                // Put hardware control code here
                water = true;
            }
            public String toString() {
                return "Greenhouse water is on";
            }
        }
        public class WaterOff extends Event {
            public WaterOff(long delayTime) { super(delayTime); }
            public void action() {
                // Put hardware control code here
                water = false;
            }
            public String toString() {
                return "Greenhouse water is off";
            }
        }
        private String thermostat = "Day";
        public class ThermostatNight extends Event {
            public ThermostatNight(long delayTime) {
                super(delayTime);
            }
            public void action() {
                // Put hardware control code here
                thermostat = "Night";
            }
            public String toString() {
                return "Thermostat on night setting";
            }
        }
        public class ThermostatDay extends Event {
            public ThermostatDay(long delayTime) {
                super(delayTime);
            }
            public void action() {
                // Put hardware control code here
                thermostat = "Day";
            }
            public String toString() {
                return "Thermostat on day setting";
            }
        }
        // An example of an action() that inserts a
        // new one of itself into the event list:
        public class Bell extends Event {
            public Bell(long delayTime) { super(delayTime); }
            public void action() {
                addEvent(new Bell(delayTime));
            }
            public String toString() { return "Bing!"; }
        }
        public class Restart extends Event {
            private Event[] eventList;
            public Restart(long delayTime, Event[] eventList) {
                super(delayTime);
                this.eventList = eventList;
                for(Event e : eventList)
                    addEvent(e);
            }
            public void action() {
                for(Event e : eventList) {
                    e.start(); // Rerun each event
                    addEvent(e);
                }
                start(); // Rerun this Event
                addEvent(this);
            }
            public String toString() {
                return "Restarting system";
            }
        }
        public static class Terminate extends Event {
            public Terminate(long delayTime) { super(delayTime); }
            public void action() { System.exit(0); }
            public String toString() { return "Terminating"; }
        }
    }
    public class No24Controller {
        public static void main(String[] args) {
            GreenhouseControls24 gc = new GreenhouseControls24();
            // Instead of hard-wiring, you could parse
            // configuration information from a text file here:
            gc.addEvent(gc.new Bell(900));
            Event[] eventList = {
                    gc.new ThermostatNight(0),
                    gc.new LightOn(200),
                    gc.new FanOn(300),
                    gc.new LightOff(400),
                    gc.new FanOff(500),
                    gc.new WaterOn(600),
                    gc.new WaterOff(800),
                    gc.new ThermostatDay(1400),
            };
            gc.addEvent(gc.new Restart(2000, eventList));
            if(args.length == 1)
                gc.addEvent(
                        new GreenhouseControls24.Terminate(
                                new Integer(args[0])));
            gc.run();
        }
    }
    ==========================================================================
    t is on
    Fan is on
    Light is off
    Fan is off
    Greenhouse water is on
    Greenhouse water is off
    Thermostat on day setting
    Restarting system
    Bing!
    

    10.9 内部类继承

    内部类构造器必须连接到指向其外围类对象的引用,所以在继承内部类的时候,事情就会变得复杂。那个指向外围类对象的“秘密的”引用必须被初始化,而在导出类中不再存在可连接的默认对象。

    /* Create a class with an inner class that has a non-default constructor
     * (one that takes arguments). Create a second class with an inner
     * class that inherits from the first inner class.
     */
    
    class FirstOuter {
        public class FirstInner {
            FirstInner(String s) {
                System.out.println("FirstOuter.FirstInner() " + s );
            }
        }
    }
    
    public class No26SecondOuter {
        public class SecondInner extends FirstOuter.FirstInner {
            SecondInner(FirstOuter x) {
                x.super("hello");
                System.out.println("SecondOuter.SecondInner()");
            }
        }
        public static void main(String[] args) {
            FirstOuter fo = new FirstOuter();
            //FirstOuter.FirstInner fs = new FirstOuter.FirstInner("s");
            No26SecondOuter so = new No26SecondOuter();
            SecondInner si = so.new SecondInner(fo);
        }
    }
    ====================================================================
    FirstOuter.FirstInner() hello
    SecondOuter.SecondInner()
    

    10.10 内部类可以被覆盖吗

    当继承了某个外围类的时候,重新定义此内部类并不会被覆盖,会产生两个独立的实体。

    当然,明确继承某个内部类是可以的。

    10.11 局部内部类

    代码块里面创建,典型的是 方法里面创建,局部内部类不能有访问说明符,因为它不是外围类的一部分。它可以访问当前代码块内的常量。

    局部内部类 和 匿名内部类的实现是一样的 ,唯一的区别是 局部内部了我们需要一个以命名的构造器,或者需要重载构造器,而匿名内部了只能用于实例初始化。

    使用局部内部类而不使用匿名内部类的另一个理由:需要不止一个内部类对象

    10.12 内部类标识符

    内部类的类文件命名 :

    外围类$内部类.class

    10.13 总结

    内部类,好!!!!!!!!!!!!!!!!难

  • 相关阅读:
    STS 创建 Maven 项目填坑
    JeeSite | 访问控制权限
    《Spring + MyBatis 企业应用实战》书评
    MyBatis-Generator 用法介绍
    Java描述数据结构之链表的增删改查
    Java中的Object类的几个方法
    设计模式之策略模式(Strategy Pattern)
    设计模式之模板方法(Template Method)
    JeeSite | 数据分页与翻页
    day 19
  • 原文地址:https://www.cnblogs.com/AronJudge/p/14398063.html
Copyright © 2011-2022 走看看