Java编程思想——内部类

序言

  1. 内部类:可以将一个类定义放在另一个类定义中。
  2. 优点:允许将逻辑上相关的类组织在一起,并控制在内部类的可见性。

1. 创建内部类

代码示例:

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-21 5:25 PM
 */
public class Parcel1 {
    class Contents {
        private int i = 11;

        public int value() {
            return i;
        }
    }

    class Destination {
        private String label;

        public Destination(String whereTo) {
            label = whereTo;
        }

        String readLabel() {
            return label;
        }
    }

    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");
    }
}

//		运行结果
//		Tasmania

  1. 外部类可以拥有返回指向内部类引用的方法。

代码示例:

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-21 5:35 PM
 */
public class Parcel2 {
    class Contents {
        private int i = 11;

        public int value() {
            return i;
        }
    }

    class Destination {
        private String label;

        public 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();
        Parcel2.Contents c = q.contents();
        Parcel2.Destination d = q.to("Borneo");
    }
}
//		运行结果
//		Tasmania
  1. 在外部类的非静态方法内以外的任何位置创建内部类的对象,必须将该对象的类型指定为OuterClassName.InnerClassName

2. 链接到外部类

  1. 内部类对象可以访问创建它的外围对象的所有成员。不需要任何特殊条件。

  2. 内部类拥有外围类所有元素的访问权。

    代码示例:

    package innerclasses;
    
    /**
     * @author vincient
     * @create 2020-04-22 4:46 下午
     */
    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;
    
            @Override
            public boolean end() {
                return i == items.length;
            }
    
            @Override
            public Object current() {
                return items[i];
            }
    
            @Override
            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();
            }
        }
    }
    
    //		运行结果
    //		0 1 2 3 4 5 6 7 8 9
    

3. 使用.this和.new

  1. 若要生成对外部对象的引用,使用类名+“.this”的方式。

代码示例:

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-22 8:55 下午
 */
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 dotThis = new DotThis();
        DotThis.Inner dti = dotThis.inner();
        dti.outer().f();
    }
}

//		运行结果
//		DotThis.f()
  1. 有时,希望其他对象创建其某个内部类的对象,使用.new获得对外部类对象的引用。

代码示例:

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-22 9:17 下午
 */
public class DotNew {
    public class Inner{

    }

    public static void main(String[] args) {
        DotNew dn = new DotNew();
        DotNew.Inner dni = dn.new Inner();
    }
}
  1. 静态内部类不需要外部类对象引用。

代码示例:

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-22 9:24 下午
 */
public class Parcel3 {
    class Contents{
        private int i = 11;
        public int value(){
            return i;
        }
    }

    class Destination{
        private String label;

        public 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. 内部类和向上转型

代码示例

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-23 12:02 上午
 */
public interface Contents {
    int value();
}

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-23 12:01 上午
 */
public interface Destination {
    String readLabel();
}

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-23 12:05 上午
 */
class Parcel4 {
    private class PContents implements Contents {
        private int i = 11;

        @Override
        public int value() {
            return i;
        }
    }

    protected class PDestination implements Destination {
        private String label;

        private PDestination(String whereTo) {
            label = whereTo;
        }

        @Override
        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();
    }
}

5. 方法和作用域中的内部类

  1. 可以在方法和作用域中定义内部类,理由如下:

    • 实现某类型的接口,可以创建并返回接口引用。
    • 创建一个类帮忙解决问题,但是又不希望这个类外部可用。
  2. 局部内部类:在方法作用域内创建的类

  3. 局部内部类不可以在方法以外被访问。

  4. 在同一子路径中任意类的内部类使用相同的类名不会出现命名冲突。

代码示例:

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-23 2:37 下午
 */
public class Parcel5 {
    public Destination destination(String s) {
        class PDestination implements Destination {
            private String label;

            public PDestination(String whereTo) {
                label = whereTo;
            }

            @Override
            public String readLabel() {
                return label;
            }
        }
        return new PDestination(s);
    }

    public static void main(String[] args) {
        Parcel5 p = new Parcel5();
        Destination d = p.destination("Tasmania");
    }
}
  1. 在任意作用域内嵌入内部类,代码示例:
package innerclasses;

/**
 * @author vincient
 * @create 2020-04-23 3:41 下午
 */
public class Parcel6 {
    private void internalTracking(boolean b) {
        if (b) {
            class TrackingSlip {
                private String id;

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

结论:内部类与别的类一起被编译。在作用域之外不可访问。此外与普通类一样

6. 匿名内部类

代码示例:

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-23 4:57 下午
 */
public class Parcel7 {
    public Contents contents() {
        return new Contents() {
            private int i = 11;

            @Override
            public int value() {
                return i;
            }
        };
    }

    public static void main(String[] args) {
        Parcel7 p = new Parcel7();
        Contents c = p.contents();
    }
}

以上写法是以下写法的简写

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-23 5:03 下午
 */
public class Parcel7b {
    class MyContents implements Contents {
        private int i = 11;

        @Override
        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();
    }
}

使用基类构造器有参的匿名内部类,代码示例:

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-23 5:33 下午
 */
public class Parcel8 {
    public Wrapping wrapping(int x) {
        return new Wrapping(x) {
            public int value() {
                return super.value() * 47;
            }
        };
    }

    public static void main(String[] args) {
        Parcel8 p = new Parcel8();
        Wrapping w = p.wrapping(10);
    }
}
package innerclasses;

/**
 * @author vincient
 * @create 2020-04-23 5:38 下午
 */
public class Wrapping {
    private int i;

    public Wrapping(int x) {
        i = x;
    }

    public int value() {
        return i;
    }
}
  1. 匿名内部类末尾的分号,代表的是表达式的结束,不是匿名内部类的结束。
  2. 匿名类中定义字段,能对其执行初始化操作。代码示例
package innerclasses;

/**
 * @author vincient
 * @create 2020-04-23 5:49 下午
 */
public class Parcel9 {
    public Destination destination(final String desc){
        return new Destination() {
            private String label = desc;

            @Override
            public String readLabel() {
                return label;
            }
        };
    }

    public static void main(String[] args) {
        Parcel9 p = new Parcel9();
        Destination d = p.destination("Tasmania");
    }
}
  1. 定义匿名内部类使用外部定义的对象,则参数引用必须为final的,注意,jdk1.8已经没有强制要求

  2. 匿名内部类没有命名构造器。代码示例:

package innerclasses;

import static net.mindview.util.Print.print;

/**
 * @author vincient
 * @create 2020-04-23 9:34 下午
 */
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");
            }

            @Override
            public void f() {
                print("In anonymous f()");
            }
        };
    }

    public static void main(String[] args) {
        Base base = getBase(47);
        base.f();
    }
}

//		运行结果
//    Base constructor, i = 47
//    Inside instance initializer
//    In anonymous f()
  1. 带实例初始化的内部类,代码示例:
package innerclasses;

/**
 * @author vincient
 * @create 2020-04-23 9:45 下午
 */
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;

            @Override
            public String readLabel() {
                return label;
            }
        };
    }

    public static void main(String[] args) {
        Parcel10 p = new Parcel10();
        Destination d = p.destination("Tasmania", 101.395F);
    }
}

//		运行结果
// 		Over budget!
  1. 匿名内部类和常规继承类相比有受限,匿名内部类既能继承类,也能实现接口。但不能两者皆备。如果实现接口,只能实现一个接口。

6.1 再访工厂方法

  1. 代码示例:

    package innerclasses;
    
    import static net.mindview.util.Print.print;
    
    /**
     * @author vincient
     * @create 2020-04-24 9:41 上午
     */
    interface Service {
        void method1();
    
        void method2();
    }
    
    interface ServiceFactory {
        Service getService();
    }
    
    class Implementation1 implements Service {
        private Implementation1() {
        }
    
        @Override
        public void method1() {
            print("Implementation1 method1");
        }
    
        @Override
        public void method2() {
            print("Implementation1 method2");
        }
    
        public static ServiceFactory factory = new ServiceFactory() {
            @Override
            public Service getService() {
                return new Implementation1();
            }
        };
    }
    
    class Implementation2 implements Service {
        private Implementation2() {
        }
    
        @Override
        public void method1() {
            print("Implementation2 method1");
        }
    
        @Override
        public void method2() {
            print("Implementation2 method2");
        }
    
        public static ServiceFactory factory = new ServiceFactory() {
            @Override
            public Service getService() {
                return new Implementation2();
            }
        };
    }
    
    public class Factories {
        public static void serviceCustomer(ServiceFactory fact) {
            Service s = fact.getService();
            s.method1();
            s.method2();
        }
    
        public static void main(String[] args) {
            serviceCustomer(Implementation1.factory);
            serviceCustomer(Implementation2.factory);
        }
    }
    
    //		运行结果
    //		Implementation1 method1
    //		Implementation1 method2
    //		Implementation2 method1
    //		Implementation2 method2
    
    package innerclasses;
    
    import static net.mindview.util.Print.print;
    
    /**
     * @author vincient
     * @create 2020-04-24 10:13 上午
     */
    interface Game {
        boolean move();
    }
    
    interface GameFactory {
        Game getGame();
    }
    
    class Checkers implements Game {
        private Checkers() {
    
        }
    
        private int moves = 0;
        private static final int MOVES = 3;
    
        @Override
        public boolean move() {
            print("Checkers move " + moves);
            return ++moves != MOVES;
        }
    
        public static GameFactory factory = new GameFactory() {
            @Override
            public Game getGame() {
                return new Checkers();
            }
        };
    }
    
    class Chess implements Game {
        private Chess() {
    
        }
    
        private int moves = 0;
        private static final int MOVES = 4;
    
        @Override
        public boolean move() {
            print("Chess move " + moves);
            return ++moves != MOVES;
        }
    
        public static GameFactory factory = new GameFactory() {
            @Override
            public Game getGame() {
                return new Chess();
            }
        };
    }
    
    public class Games {
        public static void playGame(GameFactory factory) {
            Game s = factory.getGame();
            while (s.move()) ;
        }
    
        public static void main(String[] args) {
            playGame(Checkers.factory);
            playGame(Chess.factory);
        }
    }
    
    //		运行结果
    //    Checkers move 0
    //    Checkers move 1
    //    Checkers move 2
    //    Chess move 0
    //    Chess move 1
    //    Chess move 2
    //    Chess move 3
    

7. 嵌套类

  1. 定义:声明为static的内部类。
  2. 静态内部类不持有外部类的引用。
  3. 要求:
    • 不需要外围类的对象即可以创建嵌套类
    • 嵌套类对象不可访问非静态的外围类对象

7.1 接口内部的类

  1. 嵌套内可以作为接口的一部分
  2. 接口中的类自动publicstatic

代码示例:

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-24 2:34 下午
 */
public interface ClassInInterface {
    void howdy();
    class Test implements ClassInInterface{
        @Override
        public void howdy() {
            System.out.println("Howdy");
        }

        public static void main(String[] args) {
            new Test().howdy();
        }
    }
}

//		运行结果
//		Howdy
  1. 嵌套类为接口的各种实现提供共用代码。
  2. 使用嵌套类来放置测试代码,代码示例:
package innerclasses;

/**
 * @author vincient
 * @create 2020-04-24 2:40 下午
 */
public class TestBed {
    public void f() {
        System.out.println("f()");
    }

    public static class Tester{
        public static void main(String[] args) {
            TestBed t = new TestBed();
            t.f();
        }
    }
}

//		运行结果
//		f()

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

  1. 嵌套类被嵌套多少层并不重要,它可以访问它所嵌入的外围类的所有成员。代码示例:
package innerclasses;

/**
 * @author vincient
 * @create 2020-04-24 2:59 下午
 */
class MNA{
    private void f() {

    }
    class A{
        private void g() {

        }

        public class B{
            void h() {
                g();
                f();
            }
        }
    }
}
public class MultiNestingAccess {
    public static void main(String[] args) {
        MNA mna = new MNA();
        MNA.A mnaa = mna.new A();
        MNA.A.B mnaab = mnaa.new B();
        mnaab.h();
    }
}

8. 为何需要内部类

  1. 内部类继承自某个类或者实现了某个接口。内部类的代码可以操作创建它的外围类的对象。可以说内部类提供了某种进入外部类的窗口。
  2. 切中内部类的核心的问题:如果只需要接口引用,为什么不让外部类实现接口?如果这能满足需求,那就应该这样做。
  3. 内部类实现接口和外部类实现接口的区别:不是总能拥有接口的便利性,有时需处理实现。
  4. 使用内部类最吸引人的原因:每个内部类可以独立的继承自一个接口的实现,无论外围类是否继承了一个实现,对内部类都没有影响
  5. 内部类允许继承多个非接口类型。

代码示例:

package innerclasses;

/**
 * @author vincient
 * @create 2020-04-24 3:53 下午
 */
interface A {

}

interface B {

}

class X implements A, B {
}

class Y implements A {
    B makeB() {
        // Anonymous inner class:
        return new B() {
        };
    }
}

public class MultiInterfaces {
    static void takesA(A a) {

    }

    static void takesB(B b) {

    }

    public static void main(String[] args) {
        X x = new X();
        Y y = new Y();
        takesA(x);
        takesA(y);
        takesB(x);
        takesB(y.makeB());
    }
}
  1. 如果面对多重继承抽象类或具体类,则只能使用内部类,代码示例:
package innerclasses;

/**
 * @author vincient
 * @create 2020-04-24 4:00 下午
 */
class D{

}

abstract class E{

}

class Z extends D{
    E makeE() {
        return new E() {
        };
    }
}
public class MultiImplementation {
    static void takesD(D d) {

    }

    static void takesE(E e) {

    }

    public static void main(String[] args) {
        Z z = new Z();
        takesD(z);
        takesE(z.makeE());
    }
}
  1. 如果不需要解决多实现继承问题,可以不需要使用内部类,在其他任何地方编码。使用内部类,可以获得以下特性:
    • 内部类可以有多个实例,每个实例都拥有自己的状态信息,这些状态信息独立于外围类对象中的信息。
    • 在一个外围类中可以有多个内部类,每个内部类以不同的方式实现同样的接口或者继承自相同的类
    • 创建内部类对象的时机并没有绑定到外部类对象创建
    • 内部类不存在令人迷惑的is-a关系,就是一个独立的实体。

8.1 闭包和回调

  1. 闭包是可调用对象,保留了创建闭包的作用域的信息

  2. 内部类是面向对象的闭包,它不仅包含来自外部类对象的每条信息,还自动持有对整个外部类对象的引用,有权操作所有成员,包括私有成员。

  3. java中最引人注意的争议是引入回调这种指针机制。通过回调,对象能够携带一些信息,以允许在稍后的某个时刻调用初始对象。

代码示例:

package innerclasses;

import static net.mindview.util.Print.print;

/**
 * @author vincient
 * @create 2020-04-27 8:30 上午
 */
interface Incrementable {
    void increment();
}

class Callee1 implements Incrementable {
    private int i = 0;

    @Override
    public void increment() {
        i++;
        print(i);
    }
}

class MyIncrement {
    public void increment() {
        print("Other operation");
    }

    static void f(MyIncrement mi) {
        mi.increment();
    }
}

class Callee2 extends MyIncrement {
    private int i = 0;

    @Override
    public void increment() {
        super.increment();
        i++;
        print(i);
    }

    private class Closure implements Incrementable {
        @Override
        public void increment() {
            Callee2.this.increment();
        }
    }

    Incrementable getCallbackReference() {
        return new Closure();
    }
}

class Caller {
    private Incrementable callbackReference;

    public Caller(Incrementable cbh) {
        callbackReference = cbh;
    }

    void go() {
        callbackReference.increment();
    }
}

public class Callbacks {
    public static void main(String[] args) {
        Callee1 c1 = new Callee1();
        Callee2 c2 = new Callee2();
        MyIncrement.f(c2);
        Caller caller1 = new Caller(c1);
        Caller caller2 = new Caller(c2.getCallbackReference());
        caller1.go();
        caller1.go();
        caller2.go();
        caller2.go();
    }
}

//		运行结果
//    Other operation
//    1
//    1
//    2
//    Other operation
//    2
//    Other operation
//    3

8.2 内部类和控制框架

  1. 设计模式是将变化的部分和不变的部分分离开来。所以模版方法设计模式中,模版方法是不变的部分,可重写的方法是变的部分。
  2. 控制框架:用来解决响应事件的需求。
  3. 事件驱动系统:用以响应事件的系统。
  4. 命令设计模式:请求封装为对象。

代码示例:

package innerclasses.controller;

/**
 * @author vincient
 * @create 2020-04-28 8:17 上午
 */
public abstract class Event {
    private long eventTime;
    protected final long delayTime;

    public Event(long delayTime) {
        this.delayTime = delayTime;
        start();
    }

    public void start() {
        eventTime = System.nanoTime() + delayTime;
    }

    public boolean ready() {
        return System.nanoTime() >= eventTime;
    }

    public abstract void action();
}
package innerclasses.controller;

import java.util.ArrayList;
import java.util.List;

/**
 * @author vincient
 * @create 2020-04-28 8:30 上午
 */
public class Controller {
    private List<Event> eventList = new ArrayList<>();

    public void addEvent(Event c) {
        eventList.add(c);
    }

    public void run() {
        while (eventList.size() > 0) {
            for (Event e : new ArrayList<>(eventList)) {
                if (e.ready()) {
                    System.out.println(e);
                    e.action();
                    eventList.remove(e);
                }
            }
        }
    }
}
package innerclasses;

import innerclasses.controller.Controller;
import innerclasses.controller.Event;

/**
 * @author vincient
 * @create 2020-04-28 9:41 上午
 */
public class GreenhouseControls extends Controller {
    private boolean light = false;

    public class LightOn extends Event {
        public LightOn(long delayTime) {
            super(delayTime);
        }

        @Override
        public void action() {
            light = true;
        }

        @Override
        public String toString() {
            return "Light is on";
        }
    }

    public class LightsOff extends Event {
        public LightsOff(long delayTime) {
            super(delayTime);
        }

        @Override
        public void action() {
            light = false;
        }

        @Override
        public String toString() {
            return "Light is off";
        }
    }

    private boolean water = false;

    public class WaterOn extends Event {
        public WaterOn(long delayTime) {
            super(delayTime);
        }

        @Override
        public void action() {
            water = true;
        }

        @Override
        public String toString() {
            return "Greenhouse water is on";
        }
    }

    public class WaterOff extends Event {
        public WaterOff(long delayTime) {
            super(delayTime);
        }

        @Override
        public void action() {
            water = false;
        }

        @Override
        public String toString() {
            return "Greenhouse water is off";
        }
    }

    private String thermostat = "Day";

    public class ThermostatNight extends Event {
        public ThermostatNight(long delayTime) {
            super(delayTime);
        }

        @Override
        public void action() {
            thermostat = "Night";
        }

        @Override
        public String toString() {
            return "Thermostat on night setting";
        }
    }

    public class ThermostatDay extends Event {
        public ThermostatDay(long delayTime) {
            super(delayTime);
        }

        @Override
        public void action() {
            thermostat = "Day";
        }

        @Override
        public String toString() {
            return "Thermostat on day setting";
        }
    }

    public class Bell extends Event {
        public Bell(long delayTime) {
            super(delayTime);
        }

        @Override
        public void action() {
            addEvent(new Bell(delayTime));
        }

        @Override
        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);
            }
        }

        @Override
        public void action() {
            for (Event e : eventList) {
                e.start();
                addEvent(e);
            }
            start();
            addEvent(this);
        }

        @Override
        public String toString() {
            return "Restarting system";
        }
    }

    public static class Terminate extends Event {
        public Terminate(long delayTime) {
            super(delayTime);
        }

        @Override
        public void action() {
            System.exit(0);
        }

        @Override
        public String toString() {
            return "Terminating";
        }
    }


}
package innerclasses.controller;

import innerclasses.GreenhouseControls;

/**
 * @author vincient
 * @create 2020-04-28 11:18 上午
 */
public class GreenhouseController {
    public static void main(String[] args) {
        args = new String[]{"5000"};
        GreenhouseControls gc = new GreenhouseControls();
        gc.addEvent(gc.new Bell(900));
        Event[] eventList = {
                gc.new ThermostatNight(0),
                gc.new LightOn(200),
                gc.new LightsOff(400),
                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 GreenhouseControls.Terminate(new Integer(args[0])));
        }
        gc.run();
    }
}

//		运行结果
//    Bing!
//    Thermostat on night setting
//    Light is on
//    Light is off
//    Greenhouse water is on
//    Greenhouse water is off
//    Thermostat on day setting
//    Restarting system
//    Terminating

9. 内部类继承

  1. 内部类构造器必须连接上指向其外围类对象的引用。在继承内部类的时候必须要指明这种关联。

代码示例:

package interfaces;

/**
 * @author vincient
 * @create 2020-04-28 2:36 下午
 */
class WithInner{
    class Inner{

    }
}
public class InheritInner extends WithInner.Inner {
    public InheritInner(WithInner wi) {
        wi.super();
    }

    public static void main(String[] args) {
        WithInner wi = new WithInner();
        InheritInner ii = new InheritInner(wi);
    }
}

特殊语法:enclosingClassReference.super()

10. 内部类可以被覆盖么?

代码示例:

package interfaces;

import static net.mindview.util.Print.print;

/**
 * @author vincient
 * @create 2020-04-28 4:13 下午
 */
class Egg {
    private Yolk y;

    protected class Yolk {
        public Yolk() {
            print("Egg.Yolk()");
        }
    }

    public Egg() {
        print("new Egg()");
        y = new Yolk();
    }
}

public class BigEgg extends Egg{
    public class Yolk{
        public Yolk() {
            print("BigEgg.Yolk()");
        }
    }

    public static void main(String[] args) {
        new BigEgg();
    }

}
//		运行结果
//		new Egg()
//		Egg.Yolk()

两个内部类是完全独立的实体。各自在自己的命名空间内。

完全覆盖内部类代码示例:

package interfaces;

import static net.mindview.util.Print.print;

/**
 * @author vincient
 * @create 2020-04-28 4:24 下午
 */
class Egg2 {
    protected class Yolk {
        public Yolk() {
            print("Egg2.Yolk()");
        }

        public void f() {
            print("Egg2.Yolk.f()");
        }
    }

    private Yolk y = new Yolk();

    public Egg2() {
        print("New Egg2()");
    }

    public void insertYolk(Yolk yy) {
        y = yy;
    }

    public void g() {
        y.f();
    }
}

public class BigEgg2 extends Egg2 {
    public class Yolk extends Egg2.Yolk {
        public Yolk() {
            print("BigEgg2.Yolk()");
        }

        public void f() {
            print("BigEgg2.Yolk.f()");
        }
    }

    public BigEgg2() {
        insertYolk(new Yolk());
    }

    public static void main(String[] args) {
        Egg2 e2 = new BigEgg2();
        e2.g();
    }
}

//		运行结果
//    Egg2.Yolk()
//    New Egg2()
//    Egg2.Yolk()
//    BigEgg2.Yolk()
//    BigEgg2.Yolk.f()

11. 局部内部类

代码示例:

package innerclasses;

import static net.mindview.util.Print.print;
import static net.mindview.util.Print.printnb;

/**
 * @author vincient
 * @create 2020-04-28 11:05 下午
 */
interface Counter {
    int next();
}

public class LocalInnerClass {
    private int count = 0;

    Counter getCounter(final String name) {
        class LocalCounter implements Counter {
            public LocalCounter() {
                print("LocalCounter()");
            }

            @Override
            public int next() {
                printnb(name);
                return count++;
            }
        }
        return new LocalCounter();
    }

    Counter getCounter2(final String name) {
        return new Counter() {
            {
                print("Counter()");
            }

            @Override
            public int next() {
                printnb(name);
                return count++;
            }
        };
    }

    public static void main(String[] args) {
        LocalInnerClass lic = new LocalInnerClass();
        Counter
                c1 = lic.getCounter("Local inner "),
                c2 = lic.getCounter2("Anonymous inner ");
        for (int i = 0; i < 5; i++) {
            print(c1.next());
        }
        for (int i = 0; i < 5; i++) {
            print(c2.next());
        }
    }
}

//		运行结果
//    LocalCounter()
//    Counter()
//    Local inner 0
//    Local inner 1
//    Local inner 2
//    Local inner 3
//    Local inner 4
//    Anonymous inner 5
//    Anonymous inner 6
//    Anonymous inner 7
//    Anonymous inner 8
//    Anonymous inner 9

结论:使用局部内部类代替匿名内部类的唯一理由就是是否需要有名称的构造器或者重载构造器。匿名内部类只能使用实例初始化。另一个理由就是是否需要不止一个对象。

12. 内部类标识符

  1. 由于每个类都会生成一个**.class文件,持有所有信息,关于如何创建此类型的对象的信息(此信息生成“meta-class”,称为Class**对象)。

  2. 内部类class文件命名规则:OuterClassName + ‘$’ + InnerClassName

  3. 如果内部类是匿名的,编译器生成数字作为内部类的标识符。如果内部类是嵌入在内部类中,则名称附加在外围类标识符和$之后。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值