美文网首页
Java编程思想(九) 内部类

Java编程思想(九) 内部类

作者: kaiker | 来源:发表于2022-06-12 13:22 被阅读0次
    • 将一个类的定义放在另一个类的定义内部就是内部类

    1、创建内部类

    • 典型的情况是,外部类有一个方法,该方法返回一个指向内部类的引用
    • 如果想从外部类的非静态方法之外的任意位置创建某个内部类的对象,必须具体地指明这个对象的类型OuterClassName.InnerClassName
    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
    *///:~
    

    2、链接到外部类

    • 当生成一个内部类对象时,此对象与制造它的外围对象之间就有了一种联系,所以它能访问其外围对象的所有成员而不需要任何特殊权限。
    • 当某个外围类对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用。
    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
    *///:~
    

    3、使用.this与.new

    • 如果需要生成对外部类对象的引用,可以使用外部类的名字后面加.this
    • 如果需要外部对象创建内部类对象,可以使用对象名称加.new 内部类名称进行创建。
    • 在有外部类对象之前不能创建内部类对象。如果创建的是静态内部类,可以不用对外部对象引用。

    4、内部类与向上转型

    • 内部类实现接口后,能够完全不可见。得到的只是指向基类或接口的引用,能够很方便地隐藏实现细节。
    public interface Contents {
      int value();
    } ///:~
    
    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();
      }
    } ///:~
    

    5、在方法和作用域内的内部类

    • 需要解决一个复杂的问题,想创建一个类来辅助解决,但又不希望这个类是公共可用的。
    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");
      }
    } ///:~
    

    6、匿名内部类

    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();
      }
    } ///:~
    
    • 如果定义一个匿名内部类,并且希望它使用一个在其他外部定义的对象,那么编译器要求其参数引用是final。
    • 匿名内部类只能实现一个接口。
    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");
      }
    } ///:~
    

    工厂与匿名内部类结合

    • 工厂实现和具体实现放一块了。
    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
    *///:~
    
    

    7、嵌套类

    • 如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static。通常被称为嵌套类。
    • 普通的内部类对象隐式地保存了一个引用。
    • 不需要外围类的对象,不能从嵌套类对象中访问非静态的外围对象。
    • 一个内部类被嵌套多少层都能够透明地访问所有它所嵌入的外围类的所有成员。

    8、为什么需要内部类

    • 一般情况下,内部类继承自某个类或实现某个接口,内部类的代码操作创建它的外围类的对象。所以可以认为内部类提供了某种进入其外围类的窗口。
    • 如果只是为了实现接口,外围类可以实现就不应该在内部类实现。
    • 每个内部类都能独立地继承自一个实现,无论外围类是否已经集成了某个实现,对内部类都没影响。内部类使得多重继承的解决方案变得完整。内部类允许继承多个非接口类型。
    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());
      }
    } ///:~
    
    • 内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立。
    • 可以让多个内部类以不同方式实现同一个接口,或继承同一个类。
    • 创建内部类对象的时刻并不依赖于外围类对象的创建。
    • 内部类就是一个独立的实体。

    闭包与回调

    • 闭包是一个可调用对象,记录了一些信息,这些信息来自于创建它的作用域。
    • 内部类是面向对象的闭包,不仅包含外围类的对象信息,还自动拥有一个指向此外围类对象的引用。
    • 通过回调,对象能够携带一些信息,这些信息允许它在稍后某个时刻调用初始的对象。
    import static net.mindview.util.Print.*;
    
    interface Incrementable {
      void increment();
    }
    
    // Very simple to just implement the interface:
    class Callee1 implements Incrementable {
      private int i = 0;
      public void increment() {
        i++;
        print(i);
      }
    }   
    
    class MyIncrement {
      public void increment() { print("Other operation"); }
      static void f(MyIncrement mi) { mi.increment(); }
    }   
    
    // If your class must implement increment() in
    // some other way, you must use an inner class:
    class Callee2 extends MyIncrement {
      private int i = 0;
      public void increment() {
        super.increment();
        i++;
        print(i);
      }
      private class Closure implements Incrementable {
        public void increment() {
          // Specify outer-class method, otherwise
          // you'd get an infinite recursion:
          Callee2.this.increment();
        }
      }
      Incrementable getCallbackReference() {
        return new Closure();
      }
    }   
    
    class Caller {
      private Incrementable callbackReference;
      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();
      } 
    } /* Output:
    Other operation
    1
    1
    2
    Other operation
    2
    Other operation
    3
    *///:~
    

    9、内部类的继承

    class WithInner {
      class Inner {}
    }
    
    public class InheritInner extends WithInner.Inner {
      //! InheritInner() {} // Won't compile
      InheritInner(WithInner wi) {
        wi.super();
      }
      public static void main(String[] args) {
        WithInner wi = new WithInner();
        InheritInner ii = new InheritInner(wi);
      }
    } ///:~
    

    10、内部类覆盖

    • 两个类继承,里面都有同名内部类,这两个内部类互相不会影响。

    11、局部内部类

    • 局部内部类不能有访问说明符,因为它不是外围类的一部分。
    • 理由一是需要一个已命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例初始化。
    • 使用局部内部类而不是匿名内部类的另一个理由是需要不止一个内部类对象。

    12、内部类标识符

    • 内部类也必须生成一个.class文件以包含它们的Class对象信息。
    • 命名的方式是外围类的名字 + $ + 内部类的名字
    LocalInnerClass$1.class
    LocalInnerClass$1LocalCounter.class
    

    相关文章

      网友评论

          本文标题:Java编程思想(九) 内部类

          本文链接:https://www.haomeiwen.com/subject/vatwmrtx.html