Java编程思想:第10章 内部类

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

1.可以实现隐藏

2.内部类了解外围类,并能与之通信,很多时候可以写出更加优雅和清晰的代码

10.1创建内部类

public class Outer{

  class Inner{

  }

}

如果想从外部类的"非静态方法之外"的任意位置创建某个内部类对象,那么必须具体指明这个对象的类型:OuterClassName.InnerClassName

10.2链接到外部类

内部类自动拥有对外围类所有成员的访问权,这是如何做到的呢?当外围类对象创建了一个内部类对象时,此内部类对象必定会秘密的捕获一个指向那个外围类对象的引用,在访问外部类对象成员时,就是用这个引用来访问。编译器会帮助我们处理这些细节,而我们使用时,就像是内部类本身带有的一样。所以非static内部类在创建时候必须要由外部类对象来创建。

10.3使用.this与.new

如果要使用外部类对象的引用,OuterClassName.this来获取,编译器会检查类型是否正确,无运行时开销。

创建内部类对象:要先有外部类对象Outer o = new Outer();然后用外部类对象创建内部类对象Outer.Inner i = o.new Inner();不可以用o.new Outer.Inner();

10.4内部类向上转型

当把private内部类向上转型成基类,尤其是接口的时候,内部类就有了用武之地:这个接口的实现可以完全隐藏,完全不可见,因为返回的是接口引用

参考java源码AbstractList类:

public Iterator<E> iterator() {

  return new Itr();

}

private class Itr implements Iterator<E> {

  ...

}

当我们外界使用迭代器的时候

Iterator iter = arrayList.iterator();

只能拿到接口的引用,完全不知道里面是一个private内部类,因为Itr是private的,也不能创建它。

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

局部内部类:定义在方法体或者某一作用域里,超出作用域不能使用。

注意:不能使用意味着在外部不能被访问到类型,但是该类型在JVM里是实际存在的,即使这个作用域已经结束。

10.6匿名内部类

没有名字的内部类,可以有带参构造器,可以添加并初始化域。

如果在内部类的内部要使用外部的一个对象,这个对象的引用需要是final的。构造器中使用的参数不需要是final的。

匿名内部类里不能自己添加构造器(因为不能被访问到,而且没名字),需要做一些初始化的时候,可以用代码块来实现。

匿名内部类与正规的继承相比,要么扩展类,要么实现接口,不能二者都有,并且只能实现一个接口。

10.6.1再访工厂方法

可以把工厂方法改成匿名内部类。

interface Game{boolean move();}

interface GameFactory{Game getGame();}

class Checkers implements Game{

  private Checkers(){}

  private int moves = 0;

  private static final int MOVES = 3;

  public static GameFactory factory = new GameFactory(){

    public Game getGame(){return new Checkers();}  

  };

  public boolean move(){

    return ++moves != MOVES;

  }

}

10.7嵌套类-静态内部类

1)创建静态内部类对象不需要外部类对象

2)不能从静态内部类对象访问外围内的非静态成员

普通内部类不可以有static字段,静态可以有

10.7.1接口内部的类

正常情况下,接口内部是不能放任何代码的,但是嵌套类可以放。放入接口中的任何类都是public static的。

用途:如果你想创建某些公共代码,使得它们可以被这个接口的所有实现使用,那么接口中嵌套内部类就会非常方便。

10.7.2在多层嵌套类中访问外部类成员

一个内部类被嵌套多少层并不重要,它可以透明的访问所有外围类的所有成员。

class MMA{

  private void f(){}

  class A{

    private void g(){}

    public class B{

      void h(){

        f();//直接调用 没有问题

        g();

      }

    }

  }

}

10.8为什么需要内部类

一般来说,内部类继承某个类或实现某个接口,并且可以操作外围类对象。

核心原因:内部类可以提供多重继承的能力。

比如: AbstractList里有Itr和ListItr两种迭代器,如果我们只是让AbstractList实现Iterator接口,那么只能写出一个迭代器,通过使用内部类方式可以添加多个迭代器。

10.8.1闭包与回调

如果有一个类需要实现一个接口来提供某个方法,但是发现这个方法已经被另外一个接口使用了,那么可以用内部类代替这个类去实现接口。

回调的价值在于它的灵活性---可以在运行时动态决定需要调用什么方法。

10.8.2内部类与控制框架

设计一个控制框架,要求到了设定时间就执行相应的事件:

//创建一个抽象事件类,有执行时间和延迟时间,在产生新事件的时候用延迟时间计算出执行时间,action方法由实现类实现。

public abstract class Event{

  private long eventTime;

  protected final long delayTime;

  public Event(long delay){

    this.delayTime = delay;

    start();  

  }

  public void start(){

    eventTime = System.nanoTime() + delayTime;

  }

  public boolean ready(){

    return System.nanoTime >= eventTime;

  }

  public abstract void action();

}

//创建一个控制类,循环遍历所有事件,如果事件时间到了就执行action

public class Controller{

  private List<Event> eventList = new ArrayList<>();

  public void addEvent(Event e){eventList.add(e);}

  public void run(){

    while(eventlist.size()>0){

      for(Event e : eventList){

        if(e.ready){

          e.action();

          eventlist.remove();

        }

      }

    }

  }

}

从上面这2个类的设计来看,我们完全不知道event具体做什么,但是我们整个控制框架的核心功能:"把变化的事物(event具体实现),与不变的事物(时间发生过程)"分开。而我们只需要创建不同的变化的Event,这正是内部类要做的事情:

1)控制框架里的实现是由单个类创建的,从而使得实现细节被封装起来。内部类用来表示解决问题所必须的不同action。

2)内部类可以很容易访问外部类成员,这种实现不会显得很笨拙。

控制框架:

public class GreenhouseControls extend Controller{

  private boolean light = false;

  public class LightOn extends Event{

    public LightOn(long delay){super(delay);}

    public void action(){

      //hardware control code to turn on light

      light = true;

    }

  }

  public class LightOff extends Event{..}

  private boolean water = false;

  public class WaterOn extends Event{

    public WaterOn(long delay){super(delay);}

    public void action(){

      //..

      water = true;

    }

  }

  //...其他内部类

}

控制框架中用内部类把实现细节都隐藏起来了。

那么如何使用这个框架并执行需要的事件呢:

public static void main(String[] args){

  GreenhouseControls gc = new GreenhouseControls();

  gc.addEvent(gc.new LightOn(100));

  gc.addEvent(gc.new LightOff(200));

  ...

  gc.run();

}

控制框架可以体现出内部类的价值,图形界面设计里更是让人信服。

10.9内部类的继承

时间: 2024-08-11 03:27:15

Java编程思想:第10章 内部类的相关文章

【Java编程思想】10.内部类

将一个类的定义放在另一个类的定义内部,这就是内部类. 10.1 创建内部类 内部类的名字是嵌套在外部类里面的 外部类可以有方法,返回一个指向内部类的调用.(外部类中可以调用内部类) 如果在外部类中,希望能在除了静态方法之外的任意位置创建某个内部类对象,那么可以向下面这样指明对象类型. OuterClassName.InnerClassName x = new InnerClassName(); 10.2 链接到外部类 在创建了一个内部类的对象后,内部类与制造它的外围对象(enclosing ob

Java编程思想笔记(第二章)

第二章  一切都是对象 尽管Java是基于C++的,但相比之下,Java是一种更纯粹的面向对象程序设计语言. c++和Java都是杂合型语言(hybird language) 用引用(reference)操作对象 类似遥控器(引用)来操作电视(对象) 在Java中你可以创建一个引用,但是没有与任何对象关联,比如: String s; 这个时候如果用则会报错.安全的做法是: 创建一个引用的同时并进行初始化 String s="1111"; 必须由你创建所有对象 New关键字的意思是给我一

java编程思想笔记(第一章)

Alan Kay 第一个定义了面向对象的语言 1.万物皆对象 2.程序是对象的集合,他们彼此通过发送消息来调用对方. 3.每个对象都拥有由其他对象所构成的存储 4.每个对象都拥有其类型(TYpe) 5.某一特定类型的所有对象都可以接收同样的消息. Booch提出一种更简洁的描述: 对象拥有状态(state) 行为(behavior) 和标识(identity) 每个对象都有一个接口 每个对象都属于定义了特性和行为的某个类(特性可以理解为属性的状态,行为可以理解为method) 在面向对象的程序设

Java编程思想——第17章 容器深入研究(two)

六.队列 排队,先进先出.除并发应用外Queue只有两个实现:LinkedList,PriorityQueue.他们的差异在于排序而非性能. 一些常用方法: 继承自Collection的方法: add 在尾部增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常 remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常 element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementExce

Java 编程思想 第五章 ----初始化与清理(1)

从今天开始每天一小时的java 编程思想的阅读和编码,其实就是把书上的代码抄下来. 5.5 清理:终结处理和垃圾回收 初始化和清理工作同等重要,但是清理工作却被常常忘记,但是在使用对象之后,对对象弃之不顾的做法并不是很安全.Java有自己的垃圾回收器负责回收无用的对象占据的内存资源.但也有特殊情况:假定你的内存区域不是用new获得的,这是无法用垃圾回收器释放所以java中允许在类中定义一个名为 finalize()的方法.       工作原理: 一旦垃圾回收器准备好释放对象占用的存储空间,将首

java 编程思想 一 第二章(对象)

上班之余发现有很多空闲时间,享受生活 又觉得有点空虚,而且对自己的基础知识总觉得掌握的不是很牢固,有点似懂非懂的感觉,近来刚好有时间,所以就考虑继续学习,然后再经过考虑和各大博主推荐选择了<java编程思想>这本书,在此分享学习心得跟大家共勉,也算是对自己的监督吧.(本内容需要有一定的基础才能看,类似于基础回顾,强化理解,新手可能有些地方不太能听懂) 一.什么是对象? 这并不是我们男女朋友那种对象哈哈. 简言之:万事万物皆对象. 个人理解:我们所要处理的事务或者建立的某种模型的抽象总结.具体就

Java编程思想:第9章 接口

接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 9.1抽象类和抽象方法 如果我们的基类只是希望它被继承从而通过它的接口操作导出类,它本身创建对象没有什么意义,那么我们可以把这个基类设计为抽象类.把在基类中不好实现的方法标记为abstract.这样做可以使类的抽象性更加明确. 9.2接口 interface关键字使得抽象概念更加彻底,只提供了形式,没有任何实现.但它不仅仅是极度抽象的类,它还允许创建出一个可以向上转型成多种类型的类,来实现类似于多重继承的特性. 接口中也可以包含域

《Java编程思想》第十章 内部类

1.将一个类的定义放到另一个类的内部,称为内部类.允许把一些逻辑相关的类组织在一起,并控制位于内部的类的可视性. 1 /** 2 * @author zlz099: 3 * @version 创建时间:2017年9月20日 下午4:39:35 4 */ 5 public class Parcel1 { 6 class Contents{ 7 private int i = 11; 8 public int value(){return i;} 9 } 10 class Destination{

Java编程思想 第四章

第四章 目录: 4.1 true和false 4.2 if-else 4.3 迭代 4.4 Foreach语法 4.5 return 4.6 break和continue 4.7 goto 4.8 switch 4.1 true 和 false 注意Java不允许我们将一个数字作为布尔值使用,这与C和C++ 不同(C/C++中,"真"是非零,而"假"是零).如果将数字作为布尔表达式,Java编译器会直接报错. 4.3.1 do-while和while 二者区别在于,