到现在为止,我们都是在Java文件中直接定义类。这样的类出现在包(package)的级别上。Java允许类的嵌套定义。

这里将讲解如何在一个类中嵌套定义另一个类。

嵌套

内部类

Java允许我们在类的内部定义一个类。如果这个类是没有static修饰符,那么这样一个嵌套在内部的类称为内部类(inner class)。

内部类被认为是外部对象的一个成员。在定义内部类时,我们同样有访问权限控制(public, private, protected)。

在使用内部类时,我们要先创建外部对象。由于内部类是外部对象的一个成员,我们可以在对象的内部自由使用内部类:

 
  1. public class Test
  2. {
  3. public static void main(String[] args)
  4. {
  5. Human me = new Human("Vamei");
  6. me.drinkWater(0.3);
  7. }
  8. }
  9.  
  10. class Human
  11. {
  12. /**
  13. * inner class
  14. */
  15. private class Cup
  16. {
  17. public void useCup(double w)
  18. {
  19. this.water = this.water - w;
  20. }
  21.  
  22. public double getWater()
  23. {
  24. return this.water;
  25. }
  26.  
  27. private double water = 1.0;
  28. }
  29.  
  30. /**
  31. * constructor
  32. */
  33. public Human(String n)
  34. {
  35. this.myCup = new Cup();
  36. this.name = n;
  37. }
  38.  
  39. public void drinkWater(double w)
  40. {
  41. myCup.useCup(w);
  42. System.out.println(myCup.getWater());
  43. }
  44.  
  45. private Cup myCup;
  46. private String name;
  47. }
 

上面的例子中,Cup类为内部类。该内部类有private的访问权限,因此只能在Human内部使用。这样,Cup类就成为一个被Human类专用的类。

如果我们使用其他访问权限,内部类也能从外部访问,比如:

 
  1. public class Test
  2. {
  3. public static void main(String[] args)
  4. {
  5. Human me = new Human("Vamei");
  6. me.drinkWater(0.3);
  7.  
  8. Human.Cup soloCup = me.new Cup(); // be careful here
  9. }
  10. }
  11.  
  12. class Human
  13. {
  14. /**
  15. * inner class
  16. */
  17. class Cup
  18. {
  19. public void useCup(double w)
  20. {
  21. this.water = this.water - w;
  22. }
  23.  
  24. public double getWater()
  25. {
  26. return this.water;
  27. }
  28.  
  29. private double water = 1.0;
  30. }
  31.  
  32. /**
  33. * constructor
  34. */
  35. public Human(String n)
  36. {
  37. this.myCup = new Cup();
  38. this.name = n;
  39. }
  40.  
  41. public void drinkWater(double w)
  42. {
  43. myCup.useCup(w);
  44. System.out.println(myCup.getWater());
  45. }
  46.  
  47. private Cup myCup;
  48. private String name;
  49. }
 

这里,内部类为默认访问权限(包访问权限)。我们可以在Test类中访问Human的内部类Cup,并使用该内部类创建对象。注意我们创建时如何说明类型以及使用new:

Human.Cup soloCup = me.new Cup();

我们在创建内部类对象时,必须基于一个外部类对象(me),并通过该外部类对象来创建Cup对象(me.new)。我将在下一节讲述其中的含义。

闭包

可以看到,我们直接创建内部类对象时,必须是基于一个外部类对象。也就是说,内部类对象必须依附于某个外部类对象。

内部对象与外部对象

与此同时,内部类对象可以访问它所依附的外部类对象的成员(即使是private的成员)。从另一个角度来说,内部类对象附带有创建时的环境信息,也就是其他语言中的闭包(closure)特性。可参考Python闭包

我们看下面的例子:

 
  1. public class Test
  2. {
  3. public static void main(String[] args)
  4. {
  5. Human me = new Human("Vamei");
  6. Human him = new Human("Jerry");
  7.  
  8. Human.Cup myFirstCup = me.new Cup();
  9. Human.Cup mySecondCup = me.new Cup();
  10. Human.Cup hisCup = him.new Cup();
  11. System.out.println(myFirstCup.whosCup());
  12. System.out.println(mySecondCup.whosCup());
  13. System.out.println(hisCup.whosCup());
  14. }
  15. }
  16.  
  17. class Human
  18. {
  19. /**
  20. * inner class
  21. */
  22. class Cup
  23. {
  24. public String whosCup()
  25. {
  26. return name; // access outer field
  27. }
  28. }
  29.  
  30. /**
  31. * constructor
  32. */
  33. public Human(String n)
  34. {
  35. this.name = n;
  36. }
  37.  
  38. public void changeName(String n)
  39. {
  40. this.name = n;
  41. }
  42.  
  43. private String name;
  44. }
 

运行结果:

Vamei
Vamei
Jerry

在上面的例子中,我们通过内部类对象访问外部类对象的name成员。当我们基于不同的外部对象创建内部类对象时,所获得的环境信息也将随之变化。

嵌套static类

我们可以在类的内部定义static类。这样的类称为嵌套static类(nested static class)。

我们可以直接创建嵌套static类的对象,而不需要依附于外部类的某个对象。相应的,嵌套static类也无法调用外部对象的方法,也无法读取或修改外部对象的数据。从效果上看,嵌套static类拓展了类的命名空间(name space),比如下面的Human.Mongolian:

 
  1. public class Test
  2. {
  3. public static void main(String[] args)
  4. {
  5. Human.Mongolian him = new Human.Mongolian();
  6. him.Shout();
  7. }
  8. }
  9.  
  10. class Human
  11. {
  12. /**
  13. * nested class
  14. */
  15. static class Mongolian
  16. {
  17. public void Shout()
  18. {
  19. System.out.println("Oh...Ho...");
  20. }
  21. }
  22. }
 

在定义嵌套static类时,我们同样可以有不同的访问权限修饰符。

总结

嵌套类允许我们更好的组织类

内部类实现了闭包

Java进阶07 嵌套类的更多相关文章

  1. Java进阶01 String类

    链接地址:http://www.cnblogs.com/vamei/archive/2013/04/08/3000914.html 作者:Vamei 出处:http://www.cnblogs.com ...

  2. Java中的嵌套类和内部类

    以前看<Java编程思想>的时候,看到过嵌套类跟内部类的区别,不过后来就把它们的概念给忘了吧.昨天在看<数据结构与算法分析(Java语言版)>的时候,又遇到了这个概念,当时就很 ...

  3. Java学习笔记-嵌套类

    嵌套类 嵌套类有两种类别:static and non-static,分别对应为静态嵌套类和内部类. class OuterClass { ... static class StaticNestedC ...

  4. java#内部类和嵌套类

    内容思路来自Java编程思想,个人读书做的笔记,仅个人复习之用,故他人参考请自行辨别内容是否有错误. 在类的类部可以定义类,叫做内部类.如果这个内部类被static修饰,此时内部的类叫做嵌套类. 内部 ...

  5. EffectiveJava(22)JAVA四种嵌套类的特点及用法

    嵌套类: 1.静态成员类 静态成员类是外围类的一个静态成员,遵守同样的可访问性规则 用法:a.作为公有的辅助类 内部类: 2.非静态成员类 语法上只和静态成员类的唯一区别是少一个static修饰符 a ...

  6. Java进阶01 String类(转载)

    String类包含在java.lang包中.这个包会在Java启动的时候自动import,所以可以当做一个内置类(built-in class).我们不需要显式的使用import引入String类. ...

  7. java进阶(8)--匿名类

    一.概念 1.内部类:类的内部定义了一个类 2.内部类分类:静态内部类.实例内部类.局部内部类 3.缺点:内部类的可读性比较差,尽量不用 2.匿名内部类:局部内部类的一种   二.匿名内部类的缺点 1 ...

  8. spring 笔记1: mvn 中Controller方法的参数不能是嵌套类(内部类)。

    最近做spring开发,个人认为,Controller和客户端js通讯时传递的参数类 只使用某几个方法,为了减少对其他功能的影响,想把参数类定义为Controller类的 嵌套类(内部类).但是实践发 ...

  9. JAVA 嵌套类和内部类

    一.什么是嵌套类及内部类?  可以在一个类的内部定义另一个类,这种类称为嵌套类(nested classes),它有两种类型:  静态嵌套类和非静态嵌套类.静态嵌套类使用很少,最重要的是非静态嵌套类, ...

随机推荐

  1. 本地虚拟机LNMP环境安装

      首先上传源码包到linux中(本人上传到根目录中),随意上传能找到即可 一.配置YUM源(如果已经配好就不许要重新配置) 挂载光驱要挂载到/mnt下  Mount /dev/cdrom /mnt ...

  2. getMeasuredHeight(),getScrollY(),getHeight()的区别和联系

    前言:关于控件的高度有两种获取方式,一个是获得控件的实际大小(getMeasuredHeight),就是包含显示部分和已显示的部分: 而getHeight是获得控件的显示的大小,如果控件大小超出的屏幕 ...

  3. smarty模板 变量 运算符 表达式 流程控制 函数

    ① 从配置文件中读取配置: 1,在模板页面加载配置文件 html页面 不是php页面<{config_load file='fo.conf'}> 2,在需要用到配置的地方加<{#si ...

  4. iOS系统层次架构

    本文转自:http://blog.csdn.net/lxl_815520/article/details/51172917 一,概述 iOS的系统架构分为四个层次:核心操作系统层(Core OS la ...

  5. Linux学习路线指南

    转载的,感觉写的挺好的,我自己知识复制了下,忘记了转载地址,抱歉! Linux学习路线指南 很多同学接触Linux不多,对Linux平台的开发更是一无所知.而现在的趋势越来越表明,作为一个优秀的软件开 ...

  6. ElasticSearch(十八)初识分词器

    1.什么是分词器 作用:切分词语,normalization(提升recall召回率),如给你一段句子,然后将这段句子拆分成一个一个的单个的单词,同时对每个单词进行normalization(时态转换 ...

  7. NOIP考前划水

    NOIP考前划水 君指先跃动の光は.私の一生不変の信仰に.唯私の超電磁砲永世生き! 要开始背配置了? 3行不谢. (setq c-default-style "awk") (glo ...

  8. 我的Android进阶之旅------>Android关于Log的一个简单封装

    android.util.Log类,可以方便地用于在编码调试过程中打印日志.但是在发布后的产品中,如果有太多的日志打印,则会严重地影响性能.对android.util.Log类做一个简单的封装,当产品 ...

  9. Java mail 发送邮件 主题(标题)乱码

    最近开发遇到Javamail  发送邮件标题乱码问题,腾讯.网易邮箱不会乱码,阿里邮箱  标题则会乱码.解决办法: String subject = MimeUtility.encodeWord(ma ...

  10. json遍历

    $.each(item.attributes,function (name,value) { });