Think in Java 第十章(内部类)

信仰

一个类的定义放在另一个定义内部,这就是内部类。

10.1 创建内部类
public class Parcel1{
 class Contents{
     private int i = 11;
     public int value (){ return i; }
 }
 class Destination {
     private String able;
     Destinaltion(String whereTo){
     label = whereTo;
  } 
     String readLabel (){ return label;} 
}
 public void ship(String dest){
     Contents c = new Contents();
     Destination d = new  Destination(dest);
     System.out.println(d.readLabel);
}
  public static void main(String[] args){
    Parcel1 p = new Parcel1();
    p.ship("Tasmainaaaaa");
 }
}

10.2 链接到外部类

内部类是一种名字隐藏和组织代码的模式,当生成内部类对象时,此对象可以用访问外围对象的所有成员


10.3 使用 .this与。new

对外部类的引用:外部类的名字紧跟this.
创建内部类对象:使用 .new语法


10.4 内部类与向上转型

内部类向上转型为基类或一个接口,所得到的是指向基类或接口的引用,隐藏实现细节

public interface Destination{
  String readLabel();
}
public interface Contents{
   int value();
}
//(接口的所有成员自动被设置成public)
class Parcel4{
    private class Pcontents implements Contenets {
      private int i =1;
      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 PDestinations(s);
   }
   public Contents contents(){
       return new PContents();
  }
}
public class TestPracel{
   public static void main(String[] args){
      Pracel4 p = new Parcel4();
      Contents c = p.contents();
      Destriation d =  p.destination("tasmainaaa");
 }

内部类PContents是privae,只有Parcel4 可以访问, PDesination是protected只有Parcel4及子类可以访问
private内部类可以阻止任何依赖型的代码,隐藏实现细节。


10.5 在方法和作用域内的内部类

可以在方法或在作用域定义内部类。
理由

  • 1 实现某种类型的接口,可以创建并返回对其引用。
  • 2 创建一个类来辅助解决方案,但不希望这个类时公用的。

内部类的实现。

  • 1> 定义在方法中的内部类
  • 2>定义在作用域内的类,作用域的方法在内部
  • 3>一个实现接口的匿名类
  • 4>一个匿名类,它扩展了默认构造器的类
  • 5>一个匿名类,它执行字段初始化
  • 6>一个匿名类,它通过实例初始化实现构造(匿名类不可能有构造器)

10.6 匿名内部类
public class Parcel7{
   public Contents contents(){
       return new Contents(){
           private int i =11;
           public int value(){return i;}
     };
   }
    public static void main(String[] args){
     Parcel7 p = new Parcel7();
     Contents c = p.contents();
  }
}

匿名内部类末尾的分号,并不是用来标记内部类的结束,标记的是表达式的结束,这个表达式包含了匿名内部类。

匿名内部类使用外部对象(不包含基类使用)参数引用需要final修饰。
匿名内部类实例初始化的效果就是构造器,但受到了限制(不能重载实例初始化方法,匿名内部类可以扩展类,也可以实现接口,但不能两者兼备,如果是实现接口也只能实现一个接口)

  • 10.6.1 再访工厂方法
interface Service{
    void method1();
    void method2();
}
interface ServiceFactory{
     Service getService();
}
class Implementation1 implement Service{
      private Implementation1(){}
      public method1(){ print("Implementation1 method1")}
      public method2(){ print("Implementation1 method2")}
}
  public static ServiceFactory factory = 
       new ServiceFactory(){
           public Service getService(){
             return new Implementation1 (); 
  };
}
class Implementation2 implement Service{
      private Implementation2(){}
      public method1(){ print("Implementation2 method1")}
      public method2(){ print("Implementation2 method2")}
}
  public static ServiceFactory factory = 
      new ServiceFactory(){
          public Service getService(){
           return new Implementation2 (); 
  };
}
 public class Factories{
   public static void ServiceConsumer(ServiceFactory factory){
        Service s = factory.getService();
        s.method1();
        s.method2();
   }
   public static void main(String[] args){
        ServiceConsumer(Implementation1.factory);
        ServiceConsumer(Implementation2.factory);
   }
 }

由上构造器都可以是private,并没有创建工厂的类具名

优先使用类而不是接口。如果你的设计需要接口,你必须了解它。否则,不到迫不得已,不需要将它放到你的设计中


10.7 嵌套类

如果不需要内部类对象与外围类有联系,可以将内部类对象声明为static,这就是嵌套类。
普通内部类对象隐式保存了一个引用,指向创建它的外围类对象,而内部类是static时,嵌套类就意味着

  • 1 要创建嵌套类的对象,并不需要外围类对象。
  • 2 不能从嵌套类对象中访问费静态的外围类对象
    (注意普通类内部不能有static数据和static字段,也不能包含嵌套类,但嵌套类可以包含这些东西)

10.8 为什么需要内部类

Sun公司为什么会增加这个语言特性,一般来说,内部类继承某个类或实现某个接口,内部类的代码操作创建它的外围类的对象,内部类提供了某种进入外围类的窗口。

  • 1) 如果只是需要一个接口的引用,为什么不通过外围类实现那个接口
    答案是:“如果这能满足需求,那么就应该这样做”
  • 2) 内部类实现一个接口与外围类实现这个接口有什么区别
    答案是:后者不是总能享用到接口带来的方便,有时需要用到接口的实现,所以使用最吸引人的原因是:
    每个内部类都能独立继承一个接口的实现,所以无论外围类是否已经继承了某个接口的实现,对于内部类都没有影响

也就是说内部类允许继承多个非接口类型

内部类可以获得其他一些特性

  • 1)内部类可以有多个实例,每个实例都有自己的状态信息,并且与外围类的对象信息相互独立。

  • 2)在单个外围类中,可以让内部类以不同的方式实现同一个接口,或继承同一个类。

  • 3)创建内部类对象不依赖外围类对象的创建。

  • 4)内部类没有“is-a”关系,他就是一个独立的类

  • 10.8.1 闭包与回调
    通过内部类提供的闭包功能是优良的解决方案,它比指针更灵活,更安全。


10.9 内部类的继承

内部类的构造器不需连接到指向外围类对象的引用,所以在继承内部类的时候,事情会变得有点复杂,问题在于,那个指向外围类的对象的“秘密的”引用必须被初始化,而在导出类中不再存在可连接的默认对象。要解决这个问题,必须使用特殊的语法说明它们之间的关联。

class WithInner{
  class Inner{}
}
public class InheritInner extends WithInner.Inner{
InheritInner(WithInner wi){}
   wi.super();
}
public static void main(String[] args){
   WithInner wi = new WitnInner();
   InherItInner ii = new InheritInner(wi);
  }
}

10.10 内部类可以被覆盖吗

覆盖内部类就好像是它的一个方法,其实并不起什么作用


10.11 局部内部类

可以访问当前代码块内的常量,以及此外围类所有成员。
匿名内部类和局部内部类创建的比较

interface Counter{
  int next();
}
public class LocalInnerClass{
    private int count = 0;
    Counter getCounter(final String name){
       class LocalCounter implements Counter{
           public LocalCounter(){}
           public int next(){ 
           return   count++;              
      }
    }
  }

Counter getCounter2(final String name){
   return new Counter(){
           public int next(){
             return count++; 
         }
     };
  }
}

当需要一个已命名的构造器,或者需要重载构造器,使用局部内部类,匿名内部类只能用于实例初始化。
当需要不止一个内部类对象时,使用局部内部类。


10.12 内部类标识符

每个类都会产生一个.class文件,其中包含了如何创建该类型的全部信息(此信息产生一个“meta-class”,叫Class对象)内部类必须生成一个.class文件以包含它们的Class对象信息。这些文件的命名有严格的规定:外围类的名字,加上“$”再加上内部类的名字

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352