博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java编程思想学习录(连载之:内部类)
阅读量:7009 次
发布时间:2019-06-28

本文共 6580 字,大约阅读时间需要 21 分钟。

hot3.png

Thinkpad 25 Anniversary

用thinkpad打字确实很爽啊!

注: 本文首发于 My 公众号 CodeSheep ,可 长按扫描 下面的 小心心 来订阅 ↓ ↓ ↓

CodeSheep · 程序羊



内部类基本概念

  • 可将一个类的定义置于另一个类定义的内部
  • 内部类允许将逻辑相关的类组织在一起,并控制位于内部的类的可见性
  • 甚至可将内部类定义于一个方法或者任意作用域内!
  • 当然,内部类 ≠ 组合
  • 内部类拥有其外围类 所有元素的 访问权
  • 更有甚,嵌套多层的内部类能透明地访问所有它所嵌入的外围类的所有成员

一个典型的例子:利用 Java内部类 实现的 迭代器模式

// 接口-------------------------------------------------------------public 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;  }   // 迭代器类:实现了 Selector接口的 内部类  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

.this 与 .new 的使用场景

.this用于在内部类中生成对其外部类对象的引用之时,举例:

public class DotThis {    void f() { print("DotThis.f()"); }    public class Inner { // 内部类    public DotThis outer() { // 返回外部类对象的引用      return DotThis.this; // 若直接返回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(); // 输出 DotThis.f()  }}

.new用于直接创建内部类的对象之时,距离:

public class DotNew {  public class Inner { } // 空内部类  public static void main( String[] args ) {    DotNew dn = new DotNew();    DotNew.Inner dni = dn.new Inner(); //注意此处必须使用外部类的对象,而不能直接 DotNew.Inner dni = new DotNew.Inner()  }}

嵌套类(static类型的内部类)

嵌套类是无需依赖其外部类的对象的。非static内部类通过一个特殊的this链接到其外围类的对象,而static类型的内部类无此this引用。

接口与内部类有着很有趣的关系: 放到接口中的任何类自动都是public且static,即接口中的任何类都是嵌套类,我们甚至可以在接口的内部类中去实现其外围接口,举例:

public interface ClassInInterface {  void howdy();  class Test implements ClassInInterface { // 类Test默认static,所以是嵌套类    public void howdy() {      print("Howdy!");    }    public static void main( String[] args ) {      new Test().howdy();     }  }}

方法作用域 内的内部类

可以称这类为 局部内部类

方法中定义的内部类只能在方法内被使用,方法之外不可访问,举例:

public class Parcel {  // parcel是“包裹”之意    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 ); // 只有在方法中才能访问内部类PDestination  }  public static void main( String[] args ) {    Parcel p = new Parcel();    Destination d = p.destination( "Hello" );    ...  }}

更进一步,可在任意作用域内定义内部类,举例:

public class Parcel {    private void internalTracking( boolean b ) {        if( b ) { // 局部作用域中定义了内部类,作用域之外不可访问!      class TrackingSlip {        private String id;        TrackingSlip( String s ) { id = s; }        String getSlip() { return id; }      }    }  }    public void track() { interTracking( true ); }  public static void main( String[] args ) {    Parcel p = new Parcel();    p.track();  }}

匿名内部类

直观上看,这种内部类没有“名字”,举例:

public class Parcel {    public Contents contents() {    return new Contents() { // 此即匿名内部类!!!      private int i = 11;      public int value() { return i; }    }; // !!!注意这里必须要加分号!!!  }  public static void main( String[] args ) {    Parcel p = new Parcel();    Contents c = p.contents();  }}

若想将外部的参数传到匿名内部类中(典型的如将外部参数用于对匿名内部类中的定义字段进行初始化时)使用的话,该参数必须final,举例:

public class Parcel {    public Destination destination( final String s ) { // final必须!    return new Destination() {      private String label = s;      public String readLabel() { return label; }    }; // 分号必须!  }  public static void mian( String[] args ) {    Parcel p = new Parcel();    Destination d = p.destination("Hello");  }}

匿名内部类中不可能有命名的显式构造器,此时只能使用实例初始化的方式来模仿,举例(当然下面这个例子还反映了匿名内部类如何参与继承):

// 基类---------------------------------------------abstact class Base() {  public Base( int i ) {    print( "Base ctor, i = " + i );  }  public abstract void f();}//主类(其中包含了继承上面Base的派生匿名内部类!)----------------------------------------------public class AnonymousConstructor {    public static Base getBase( int i ) { // 该处参数无需final,因为并未在下面的内部类中直接使用!    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();  }}// 输出------------------------------------------Base ctor, i = 47 // 先基类Inside instance initializer // 再打印派生类In anonymous f()

匿名内部类 + 工厂模式 = 更加简洁易懂:

// Service接口---------------------------------------------------interface Service {  void method1();  void method2();}// ServiceFactory接口---------------------------------------------------interface ServiceFactory {  Service getService();}// Service接口的实现---------------------------------------------------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 ) {    serviceComsumer( Implementation1.factory );    serviceComsumer( Implementation2.factory );  }}

总结:为什么需要内部类

内部类可以独立地继承自一个接口或者类而无需关注其外围类的实现,这使得扩展类或者接口更加灵活,控制的粒度也可以更细!

注意Java中还有一个细节:虽然Java中一个接口可以继承多个接口,但是一个类是不能继承多个类的!要想完成该特性,此时除了使用内部类来“扩充多重继承机制”,你可能别无选择,举例:

class D { }               // 普通类abstract class E { }      // 抽象类class Z extend 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() );  }}

转载于:https://my.oschina.net/hansonwang99/blog/1610718

你可能感兴趣的文章
Ubuntu下安装Python的Tkinter和Pmw库
查看>>
安装Nginx+Lua开发环境
查看>>
nginx nginx.pid无故文件丢失,日志无法正常轮转
查看>>
我的友情链接
查看>>
XML中元素VS属性
查看>>
wepy - 小程序快速开发框架
查看>>
nodejs找不到express命令
查看>>
ubuntu13.04通过lxc搭建容器java运行环境
查看>>
RHCE官方培训笔记---分享
查看>>
top命令是Linux下常用的性能分析
查看>>
使用memcached缓存tomcat7会话信息
查看>>
Fatal Python error: pycurl: libcurl link-time version is older than compile-time version
查看>>
CentOS7:搭建SVN + Apache 服务器
查看>>
想要成为一个合格的软件架构师必须知道的事情
查看>>
cachestat、cachetop、pcstat-linux系统缓存命中率分析工具
查看>>
我的友情链接
查看>>
GET & POST
查看>>
z-index 属性
查看>>
什么是Neo4j
查看>>
为了dede系统安全把data目录迁移到web以外目录
查看>>