Thinking in Java 整理笔记:内部类

Posted Chouney

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Thinking in Java 整理笔记:内部类相关的知识,希望对你有一定的参考价值。

1.一般指明一个内部类对象:OuterClassName.InnerClassName
2.内部类拥有其外围类的所有元素的访问权。
3.如: interface Selector  void next(); public class Sequence  private int i = 9;  public class SequenceSelector implements Selector     public void next()    i=i-1;    System.out.println("next!!!");     private void end()    System.out.println("end!!!!!!!!!");      public Selector selector()   return new SequenceSelector();    public static void main(String[] args)   Sequence sequence = new Sequence();   Selector selector = sequence.selector();   selector.next();
  结论 内部类可以访问其外围类的方法和字段(多层也可以)。
4.如果你需要生成对 外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this: 如:return Sequence.this; // 返回的是Sequence对象的引用
5.若想创建某个对象的某个内部类对象,则用.new语法 如: DotNew dn = new DotNew(); DotNew.Inner dni = dn.new Inner(); PS:这里 必须使用外部类的对象来创建该内部类对象,同时也解决了内部类名字作用域的问题 在拥有外部类对象之前是不可能创建内部类对象的。因为内部类对象会暗暗地连接到创建它的外部类对象上。(当然, 嵌套类(静态内部类)不需要对外部类对象的引用)
6.内部类可以(通常)对某个接口的实现,而对外能够完全不可见,方便的隐藏实现的细节
7.如: public class Sequence  private int i = 9;   private class SequenceSelector implements Selector      public void next()    this.end();      private void end()    System.out.println("end!!!!!!!!!");      public Selector selector()   return new SequenceSelector();  
//main.java package test;
import test.Sequence.*;
public class mai
 public static void main(String[] args)   Sequence sequence = new Sequence();   Selector selector = sequence.selector();   selector.next();  
这里内部类SequenceSelector是private 除了其外围类Sequence没人能访问他(若内部类是protect,则除了外围类及其子类以及同包的类能访问)因此,private内部类给类的设计者提供一种途径,通过这种方式可以完全阻止任何依赖于类型的编码,并且完全隐藏了实现的细节。 PS:这里selector方法返回值若没有向上转型为接口类型,主函数中依然无法获得private内部类
8.在方法和作用域内的内部类: 可以在一个方法里面或者在任意作用域内定义内部类。理由如下: 1)为了实现某类型的接口,可以创建并返回对其的引用。 2)要解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类是公共可用的。 PS:匿名类不可能有构造器
8.1 在方法的作用域内创建一个完整的类( 局部内部类): 若这样类则是该方法的一部分,而不是外围类的一部分,在方法之外不能访问该类
8.2 在任意作用域内嵌入一个类,如:   if(b)    class TrackSlip     private String id;     TrackingSlip(String s)      id = s;         String getSlip()return id;        TrackSlip ts= new TrackSlip("slip");    String s = ts.getSlip();   但是在定义TrackSlip作用域之外,他是不可用的,除此之外和普通的类一样
8.3匿名内部类:   public Contents contents()    return new Contents()     ...     ...       上例创建了一个 继承自Contents的匿名类的对象,通过new表达式返回的引用被自动向上转型为对Contents的引用
8.4基类为带参数的匿名内部类:只需传合适的参数给基类构造器即可 基类如下: public class Sequence  private int i;  public Sequence(int x)   i =x;   匿名类如下: System.out.println(new Sequence( 33)    ...  
8.5在匿名类中定义字段是,可以进行初始化,但若使用的是一个在外部定义的对象传进来。编译器会要求其参数引用是final
8.6 若想在在匿名类中做类似构造器的行为(匿名类中没有构造器,因为根本没名字),需通过 实例初始化:  public static Sequence show()   return new Sequence(2)                 System.out.println("initializer");           ;  
9. 工厂设计模式可以用匿名内部类进行改进: 在service实现添加一个工厂实现对象,用匿名内部类定义方法重载。
10.优先使用类而不是接口
11.如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static,通常称为嵌套类。 区别 普通的内部类对象隐式的保存了一个引用,指向它的外围类对象。单当内部类是static的时,就不是这样了: 嵌套类意味着: 1)要创建嵌套类的对象,并不需要其外围类的对象 2)不能从嵌套类的对象中访问非静态的外围类对象(这是由“静态方法不能访问非晶态成员”语法限定) 还有一个区别:普通内部类的字段与方法,只能放在类的外部层次上,所以普通内部类不能有static数据和static字段,也不能包含嵌套类(因为外围类尚未创建,内部类又依赖于外类)。但是嵌套类可以包含所有这些东西
静态内部类可以直接访问,不用考虑外围类, 也可以使用一个静态方法返回其静态类(没有.this用法)
12.接口内部的类: 嵌套类可以作为接口的一部分,并且自动地是public和static的。(因为类是static的,只是将嵌套类置于接口的命名空间内,并不违反接口的规则)。 甚至可以在内部类中实现其外围接口。
13.嵌套类可以用来放置测试代码。
14.为什么需要内部类:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了(接口的)实现,对于内部类都没有影响,内部类有效地实现了“多重继承”。 除此之外内部类的特性还有: 1)内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围类对象的信息相互独立。 2)在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或继承同一个类。 3)创建内部类对象的时刻并不依赖于外围类对象的创建。 4)内部类就是一个独立的实体。
15.闭包与回调: 闭包是一个课调用的对象,记录了一些信息,这些信息来自于创建它的作用域。 所以内部类是面向对象的闭包,因为它不仅包含外围类对象(创建内部类的作用域)的信息,还自动拥有一个指向次外围类对象的引用,在此作用域内,内部类有权操作所有的成员,包括private成员。
16.内部类在控制框架中的运用: 控制框架:用来响应时间的需求。主要用来响应事件的系统被称作 事件驱动系统。 考虑一个控制框架,他的工作就是在事件“就绪”的时候执行时间,然后对于要控制什么,控制框架并不包含任何具体的信息。那些信息使在实现算法的action()部分时,通过继承来提供的。 首先:接口描述要控制的时间Event(抽象)。 其次定义了一个实际控制框架: public class Controller  private List<Event> env = new ArrayList<Event>();  public void addEvent()   ...    public void run()   ...   而内部类要做的事情,就是在一个子控制框架中通过实现不同的Event内部子类来表现不同的行为 内部类允许: 1)控制框架的完整实现是有单个的类创建的,从而使得实现的细节被封装了起来。内部类用来表示解决问题所必须的各种不同action() 2)内部类能够很容易地访问外围类的任意成员。
实例: public class GreenController extends Controller  ...  public class LightOn extends Event   ...    ...
17.内部类的继承 若要继承内部类,则无法编译默认构造器,因为内部类指向外围类对象的“秘密的”引用必须被初始化,必须如下才行: public class Outter  class Inner public class test extends Outter.Inner  public test(Outter wi)   // TODO Auto-generated constructor stub   wi.super();  
18.当继承了某个外围类的时候,子类方法并没有覆盖内部类的方法,这两个内部类是完全独立的两个实体,具体需要看如何调用(如显式地声明继承某个内部类)。
19.使用局部内部类而不是用匿名内部类的2个理由: 1)需要一个已命名的构造器。 2)需要不止一个该内部类的对象
20.内部类标示符 每个类都会产生一个.class文件,内部类也会,即外围类的名字加上“$”再加上内部类的名字。若内部类是匿名的,则编译器会简单地产生一个数字作为其标识符。(Unix系统中需要对$做转义)

以上是关于Thinking in Java 整理笔记:内部类的主要内容,如果未能解决你的问题,请参考以下文章

Thinking in Java 整理笔记:类型信息

Thinking in Java 整理笔记:类型信息

Thinking in Java 整理笔记:字符串

Thinking in Java 整理笔记:字符串

Thinking in Java 整理笔记:通过异常处理错误

Thinking in Java 整理笔记:通过异常处理错误