《JAVA编程思想》第四版学习 需要我记住的something –内部类

一. 内部类:在其它类内定义的类,不同于组合。虽然看上去象某种代码隐藏机制,但可以实现更多功能 -了解包含它的类并可与之交换数据,而且内部类的代码可以更优雅、清晰。

 

二.内部类定义:包含在其它类内。使用与非内部类没有太大区别。
      典型用法:outer class通过方法返回inner class的引用。

      区别之一:内部类名嵌套在外部类(outer class)内,在Out class的non-static方法之外用OuterClassName.InnerClassName的形式定义内部类对象。

 

       注意,非static内部类只能在Out class的non-static方法中生成对象;在其它类中,也必须使用Out class的外部类对象实例。这就保证了下面所说的链接问题。

      区别之二:内部类可以为private和protected。

 

      Inner Class只是一种名称隐藏(name-hiding)和组织代码方式?NO。
      内部类对象有一个到创建它的外部类对象的链接(link to the enclosing object that made it),因而可以直接的、没有任何限制地访问该外部类对象的成员,而且内部类可以访问outer class的所有成员(包括private)(C++的嵌套类没有这个特性);而outer class访问inner class的成员,必须创建Inner class的对象,可以访问任何成员(包括private)。

      内部类对象中隐式包含了一个外部类对象的引用。内部类对象构建需要outer class对象的引用,如果没有,编译报错(非静态inner class)。

     .this和.new:前者用来返回Outer class引用,编译期可知道和检查正确类型,无运行时开销;后者用来由outer class对象创建其内部类的对象,OutClassObject.new InnerClassName ()(注意,不能用outClassObj.new OutClassName.InnerClassName())。

 

      嵌套类(nested class):static inner class,其对象创建不需要outer class对象引用,也可在static方法中创建。


三. 内部类与upcasting
      类实现了接口(interface),其它方法就可以用该interface作为参数,而不一定必须用该类(包括类对象定义)(类似继承)。可以利用upcasting->interface。

      upcasting内部类->基类或者接口(尤其是后者),使内部类有了用武之地。实现接口内部类可以完全不可见、不可用(通过private或protected),所获得的只是基类或接口的引用(通过private,无法进行downcasting,protected,同一个包内,或者继承类可以进行downcasting),方便隐藏实现细节。

      接口成员自动为public。

      private内部类可以阻止任何依赖于类型的代码,进行所有实现细节的隐藏。而且,扩展接口也没有任何意义,因为无法访问pubic接口之外的方法,这可以使JAVA产生更有效率的代码

 

四. inner class可以在任意作用域内定义(如方法内)。
      两个理由:1. 实现一个接口
                     2. 需要一个不公开的类辅助解决复杂的问题

 

     inner class形式:
      1. 方法内的内部类; 2. 方法中的一个作用域内的内部类; 3. 实现接口的匿名内部类; 4. 继承的匿名内部类(基类含有参的构造器); 4. 进行成员初始化的匿名内部类; 5. 使用实例初始化块进行构造的匿名内部类(匿名类没有构造器)。

 

      局部内部类(local inner class) :在方法内或方法的一个作用域中定义的内部类。局部内部类在域外不可见并不代表其对象也不可用。条件域内定义的内部类不代表它是条件创建的。

      匿名内部类(anonymous inner class) :new T(){...}; {...}为匿名内部类的定义,";"不可少(;只是该语句的结束,而不是用来表示匿名内部类的结束,所以没有什么特殊的地方),创建一个继承自T的匿名类的对象,得到的引用可自动upcast to T。是前面定义内部类的一种简写,只是该类没有名称。
前面是基类构造器为默认构造器的情况,当基类构造器有参数时:new T(args){...};此时会调用基类相应构造器。
      匿名内部类初始化 :当需要用到外部定义类的对象时,传递的引用参数必须为final,否则编译报错;匿名类不能有命名的构造器(当然不能,类本身就没有名字),可以通过实例初始化(instance initialization)来完成构造器的功能。由于实例初始化不能重载(不代表只能有一个Instance initialization clause),所以匿名内部类只能有一个构造器。
      匿名内部类只能在继承类和实现接口中2选一,且只能实现一个接口。

      prefer classes to interfaces. (宁愿选择类,而不是接口?)

 

五.嵌套类(nested class):static inner class。有点类似C++嵌套类的概念,但Java的嵌套类可以访问outer class的所有成员(包括private,当然只能通过外部类对象访问non-static成员)。
      1. 不需要通过outer class对象来创建嵌套类对象(.new不可用?);
      2. 不能通过嵌套类对象访问non-static outer class对象(意思是像非嵌套类那样直接访问);
      3. 嵌套类对象中不包含outer class对象引用(.this不可用)。
      4. 非嵌套内部类不能有static成员、方法和嵌套类(fields、methods级别必须与class本身一致,non-static不能含有static,non-static、static内可以含有non-static)。

      嵌套类可以位于接口内部,不违反接口的规则(不能定义接口实例?),只代表把嵌套类位于接口的命名空间下,位于接口内部的类自动为public static(public嵌套类),而且嵌套类本身就可以实现该接口,好处在于可以在嵌套类内编写该接口所有实现中都要用到的代码。
      嵌套类的另一个用途:编写测试代码。 为每个类编写main函数增加代码长度,可以把main放在嵌套类内,要测试该类运行该嵌套类即可;而在发布的时候只要在打包前简单的删除该嵌套类的.class文件即可。

     多重嵌套的类(non-static和static)可以没有限制的访问任何外层类的所有对象。

 

六.为什么用内部类?
       不是总是直接和接口打交道,有时候需要用的是接口的实现。(可以实现多个接口,但不能继承多个类)
       What is it that distinguishes an inner class implementing an interface from an outer class implementing the same interface? The answer is that you can't always have the convenience of interfaces-sometimes you're working with implementations.

      理由:Each inner class can independently inherit from an implementation. Thus, the inner class is not limited by whether the outer class is already inheriting from an implementation.  

      即:每个内部类可以独立继承自一个实现,不受outer class是否已经继承另一实现的限制。从效果上来说,inner class提供了多继承(multiple-inheritance,继承自多个类)的能力,提供了另一种实现多个接口的方法(相比多继承,这个似乎没那么重要,因为多继承只能通过内部类来实现)。

 

      额外特性:
      1. 内部类可以有多个实例,每个实例可以拥有独立于outer class对象的不同信息;
      2. 一个outer class可以有多个内部类,每个内部类可以以不同的方式实现同一个接口或者继承同一个类(参见习题22,两个内部类不同方式实现同一个接口,只有内部类才能完成这些);
      3. 内部类实例创建时间并不受到外部类对象创建的限制;
      4. 用内部类不会制造"is-a"关系的混乱,每个内部类都是个实体。

 

七.闭包(closure)和回调(callback)
      闭包是一种可调用的对象,它记录了来自创建它的作用域的一些信息。
      内部类是一种面向对象的闭包,不仅包含了外部类的信息,而且通过包含一个指向外部类对象的引用,可以操作所有成员,包括private。
      回调,通过其它对象携带的信息,可以在稍后的某个时刻调用初始对象。

 

      Java不支持指针类型,不能通过指针来实现回调。但内部类提供的闭包是种比较好的解决方案,更灵活,更安全(参见例callbacks)。

      回调的价值在于灵活性,可以在运行时决定需要调用的方法。 GUI编程将体现得更明显。

 

八.内部类与控制框架(control frameworks)
      一个应用程序框架(application framework)是指一个用来解决一个特定类型问题的类或类的集合。典型的应用方法是,继承其中一个或多个类,重写某些方法。重写方法的代码将通用解决方案特殊化,来解决特定问题。例如模板函数模式。 设计模式将不变的和变化的事情分开。
      控制框架是用来响应事件的一类特殊的应用程序框架 。主要用来响应事件的系统称为事件驱动系统(event-driven system),如GUI。

      内部类使得控制框架的创建和使用变得简单 。控制框架本身不包括要控制的事物的特定信息。这些信息在继承过程中,由算法的action()部分实现时提供。控制框架中变化的事情是各种事件对象的不同action,这通过创建不同event继承类来实现。(例event)
      控制事件用abstract类代替接口?

 

      内部类在控制框架中两个作用:
      1. 用来表示解决问题所需的各种不同的action()。
      2. 内部类可以直接访问外部类的所有成员,因而使得实现变得更灵活。

      参见greenhouse(温室)的例子。

 

九.内部类的继承
      内部类指向outer class object的引用必须初始化,而在它的继承类中并不存在要联接的缺省对象,必须使用特殊的语法明确指出这种关联。
      继承自内部类的类构造器不能是默认构造器,要有个outer class的引用作为参数,而且必须加上enclosingClassReference.super();语句,编译才能通过。


十.内部类能override?继承outer class,像重写方法一样重写内部类并不起作用,此时两个内部类只是两个独立的实体。可以显式指定内部类的继承关系,然后通过复写base inner class的方法,来实现多态。 参见例BigEgg2.

 

十. 局部内部类
      局部内部类(local inner class)不能有访问限定符;有访问局部final变量和outer class所有类的权限;可以有命名的构造器;在方法外不能访问。


     绝大部分情况下,可以用匿名类来替代局部内部类,除非:
     1. 需要命名的构造器,或者需要重载构造器
     2. 需要多个内部类的对象

此时就要用Local Inner class。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值