该篇文章涉及到了Java可访问特性以及内部类的一些内容,向读者展示了一个内部类的非凡的现象,通过这个例子,使开发者了" />
龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > JAVA开发 >

通过内部类的一个例子展示java中的可访问特性

时间:2009-12-23 15:42来源:未知 作者:admin 点击:
分享到:
?XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" /> 该篇文章涉及到了Java可访问特性以及内部类的一些内容,向读者展示了一个内部类的非凡的现象,通过这个例子,使开发者了

<?XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" /> 

该篇文章涉及到了Java可访问特性以及内部类的一些内容,向读者展示了一个内部类的非凡的现象,通过这个例子,使开发者了解到一些他们以前可能没有注重到的细节,也许可以帮助开发者更透彻的了解java的可访问特性、内部类和虚拟机。并且通过对这些细节的分析,可能会对开发者思考、分析问题,以及适当的使用工具有所启迪。
  
  java的访问修改符(Access modifier)包括:Default-Access、public、private、protected四种。并不是所有的情况都可以使用全部四种访问修改符,有的情况下使用某些访问修改符是没有意义的,例如:假如一个类不是内部类,则不能使用private作为该类的访问修改符,编译下面的代码:
  private class test
  { ... }
  jdk编译器将给出“modifier private not allowed here”错误提示。因为private特性只能由定义它的那个类使用,假如上面的代码通过编译,则不会有任何情况可以使用test类,那么也就不会有任何意义。
  
  假如一个类没有定义任何构造函数,则编译器将生成一个缺省的构造函数,该构造函数的访问修改符和类的访问修改符相同,例如:
  class test将生成test()构造函数public class test将生成public test()构造函数。
  在使用内部类的情况,上述的特性将使编译器表现出一个非凡现象。需要说明的是,下面的例子仅针对Windows系统下jdk编译器,作者并没有尝试使用其他的编译器的情况。但由于java编译器生成的是class文件这种中间形式的代码,所以下面的讨论应该适用于任何符合java标准的编译器。
  编译下面的代码:
  public class Wrapper
  {
  private class InnerClass
  {}
  
  private void testInnerClass()
  {
  InnerClass inner = new InnerClass();
  }
  
  public static void main(String[] args)
  {
  Wrapper wrapper = new Wrapper();
  wrapper.testInnerClass();
  }
  }
  将产生三个class文件:Wrapper、Wrapper$InnerClass和Wrapper$1。
  对于前两个文件,了解内部类的读者都会理解,但第三个类Wrapper$1的作用是什么呢?
  使用java的反射机制,或者使用javap反汇编器,将发现Wrapper$1类没有任何成员变量和方法,而Wrapper$InnerClass则除了有一个private Wrapper$InnerClass()构造方法外,还有一个Wrapper$InnerClass(Wrapper$1)构造方法,使用javap,你将发现Wrapper$InnerClass(Wrapper$1)并没有使用Wrapper$1类型的参数,而只是直接调用了private Wrapper$InnerClass()。假如读者仔细思考一下创建一个新的类实例的过程,大概已经明白了产生上述现象的原因:当程序试图创建一个Wrapper$InnerClass的类实例时,却不能使用其缺省的构造函数,因为Wrapper$InnerClass()是private的,不能由外部使用。因此编译器不得不再生成一个可访问的构造函数,由于这里只有Wrapper类的private void testInnerClass()方法使用了new InnerClass(),所以编译器只(需)为这个新的构造函数生成了Default-Access的访问修改符。同时,为了和已有的缺省构造函数有所区别,就加入了一个Wrapper$1类型的参数,为此,编译器还要生成一个Wrapper$1类。
  
  为了更简单,(也许)更清楚的看到编译器生成的class代码工作的原理,读者可以使用java反编译器,来看看class反编译后生成的java源程序,下面是作者使用Jad反编译后生成的Wrapper类的代码:
  // Decompiled by Jad v1.5.7d. Copyright 2000 Pavel Kouznetsov.
  // Jad home page: http://www.geocities.com/SiliconValley/Bridge/8617/jad.Html
  // Decompiler options: packimports(3)
  // Source File Name: Wrapper.java
  
  public class Wrapper
  {
  private class InnerClass
  {
  
  private InnerClass()
  {
  }
  
  InnerClass(_cls1 _pcls1)
  {
  this();
  }
  }
  
  public Wrapper()
  {
  }
  
  private void testInnerClass()
  {
  InnerClass innerclass = new InnerClass(null);
  }
  
  public static void main(String args[])
  {
  Wrapper wrapper = new Wrapper();
  wrapper.testInnerClass();
  }
  
  // Unreferenced inner classes:
  
  /* anonymous class */
  class _cls1
  {
  }
  
  }
  
  显然,Wrapper$1类不会有任何实际的作用。
  

精彩图集

赞助商链接