zoukankan      html  css  js  c++  java
  • Java中的嵌套类和内部类

    以前看<Java编程思想>的时候,看到过嵌套类跟内部类的区别,不过后来就把它们的概念给忘了吧。昨天在看<数据结构与算法分析(Java语言版)>的时候,又遇到了这个概念,当时就很大的疑惑:嵌套类跟内部类有什么区别?只有是否有关键字static的区别吗?

    所以今天找了个时间查了一下两者的详细区别,总结在这篇博客中,既方便自己的复习和学习,也启示他人吧。

    1,概念:

    定义在一个类内部的类,叫作“嵌套类”。嵌套类分为两种:static的和非static的。后者又有一个专门的名字,叫作“内部类”。所以从概念可以看出,嵌套类跟内部类是所属关系,后者包含于前者。示例代码如下:

    1 class OuterClass {
    2     ...
    3     static class StaticNestedClass {
    4         ...
    5     }
    6     class InnerClass {
    7         ...
    8     }
    9 }
    View Code

    同时,嵌套类是其所在类的成员。内部类可以访问所在类的所有成员,即使该成员是private的。而static嵌套类则不得访问所在类的成员。同时,嵌套类,static和非static的,都可以被声明为private、public、protected和default的。

    2,为什么要使用嵌套类?

    好处应该都比较文本化吧,以后在使用的过程中去理解和体会吧:对只在一个地方使用的类进行逻辑上的分组;增加了封装性;易于阅读和维护。

    3,static嵌套类:

    因为static嵌套类不能直接访问所在类的非static成员变量和方法,所以static嵌套类必须通过绑定所在类的实例来进行访问。而对于所在类的静态成员和方法包括private、protected和public的,可以访问。因为它也有static修饰。

    static嵌套类通过写出封装的类名来进行实例化和访问其内部成员:

    1 OuterClass.StaticNestedClass nestedObject =
    2      new OuterClass.StaticNestedClass();
    View Code

    4,内部类:

    因为内部类是所在类的成员,所以它可以访问所在类的任意变量和方法,但是它本身却不能定义任何static的变量或方法。

    同时,内部类的实例化方式也与static嵌套类有所不同:

    1 OuterClass outerObject=new OuterClass();
    2 OuterClass.InnerClass innerObject = outerObject.new InnerClass();
    View Code

    static嵌套类与non-static嵌套类,在形式上只有是否含有static关键字的区别,但是JVM在初始化时两者还是有差别的:差别就是后者在实例化时会自动地与外围实例建立一种联系,且这种联系不得修改。JVM在实例化non-static嵌套类时会生成一个指向外围实例的对象引用(this),保存这种引用将会消耗时间和空间,同时,在外围实例满足垃圾回收的条件时仍然得以留存。

    5,内部类的分类:

    以前曾经接触过内部类的分类,这里一并总结一下:

    以前的所谓的一些面试宝典里面差不多都是将内部类分为四个种类:

    静态内部类(既static嵌套类)、成员内部类(既上述内部类)、局部内部类和匿名内部类。前两者都已经介绍过了,下面专门看一下后面两者。

    5.1,局部内部类:

    定义在方法内部的类叫作“局部内部类”。它的作用域仅限于方法作用域内,只能在方法的作用域内定义和实例化,是用处最小的类类型。和局部变量一样,它不能被修饰为private, public, protected和static的,并且只能访问方法内部定义的final变量。

     1 class LocalInner
     2 {
     3     int a = 1;
     4 
     5     public void doSomething()
     6     {
     7         int b = 2;
     8         final int c = 3;
     9         // 定义一个局部内部类
    10         class Inner3
    11         {
    12             public void test()
    13             {
    14                 System.out.println("Hello World");
    15                 System.out.println(a);
    16 
    17                 // 不可以访问非final的局部变量
    18                 // error: Cannot refer to a non-final variable b inside an inner
    19                 // class defined in a different method
    20                 // System.out.println(b);
    21 
    22                 // 可以访问final变量
    23                 System.out.println(c);
    24             }
    25         }
    26 
    27         // 创建局部内部类的实例并调用方法
    28         new Inner3().test();
    29     }
    30 }
    31 
    32 public class LocalInnerClassTest
    33 {
    34     public static void main(String[] args)
    35     {
    36         // 创建外部类对象
    37         LocalInner inner = new LocalInner();
    38         // 调用外部类的方法
    39         inner.doSomething();
    40     }
    41 
    42 }
    View Code

    5.2,匿名内部类:

    顾名思义,匿名内部类就是没有名字的局部类。它不使用关键字class, extends, implements以及构造函数。

    它通常作为方法的一个参数传入,比如在android开发中对一个Button添加一个OnClickListener监听器。

    匿名内部类隐匿的继承了一个父类或者实现了一个接口。比如:

     1 mUiHandler.post(new Runnable{
     2     @override
     3     public void run(){
     4     //
     5     }
     6 
     7 });
     8 
     9 AsyncClient.get(url, new JsonHttpResponseHandler() {
    10             @Override
    11             public void onSuccess(int statusCode, Header[] headers,
    12                     JSONObject response) {
    13                 // TODO Auto-generated method stub
    14                 super.onSuccess(statusCode, headers, response);}} );
    View Code

    内部类通过将相关的类组织在一直,从而降低了命名空间的复杂性。

    6,内部类的序列化问题。

    对任何种类内部类(包括局部内部类和匿名内部类)的序列化都是不被鼓励的。因为java编译器在对内部类进行编译的时候,将进行“合成构造”。合成构造使得java编译器实现了java的新特性,但是却没有对JVM做出相应的改变。然而,不同的java编译器对合成构造是有差别的,因而,如果对内部类进行了序列化,将使得不同的JRE实现中存在兼容性问题。

    本文是在参考了大量他人的劳动成果之上的而写成的,主要的参考文献有:

    http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html;

    http://www.cnblogs.com/mengdd/archive/2013/02/08/2909307.html。

  • 相关阅读:
    Vagrant安装virtualbox
    SQLSERVER排查CPU占用高的情况
    删除重复记录,只留一条
    ASCII码对应表chr(9)、chr(10)、chr(13)、chr(32)、chr(34)、chr(39)、……
    手机和PC端的录屏软件
    2017年初面试总结
    Python面向对象
    Python字体颜色
    Python第二模块总结
    Fiddler使用教程(转)
  • 原文地址:https://www.cnblogs.com/littlepanpc/p/3778472.html
Copyright © 2011-2022 走看看