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系统中需要对$做转义)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值