CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
山寨机中的战斗机! 程序优化工程师到底对IT界有没有贡献
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  Java >  J2SE / 基础类

讨论??内部类与外部类的关系。

楼主Sanco(十扇门)2005-06-14 11:32:04 在 Java / J2SE / 基础类 提问

以下代码编译通过,但运行时会有java.lang.StackOverflowError   异常。  
  但如果将   //1   改为:private   static   Scroll   acc   =   new   Scroll();  
                    //2   改为:private   static   class   Scroll   extends   Test{  
  编译运行均可通过。  
  能解释下这是为什么吗?欢迎讨论。  
   
  public   class   Test   implements   Cloneable{  
           
          int   i   =   0;  
          private   Scroll   acc   =   new   Scroll();     //     1          
           
          public   Object   clone(){  
                  try{  
                          return   super.clone();  
                  }catch   (   CloneNotSupportedException   e){  
                          return   null;  
                  }  
          }  
           
          public   Scroll   getScroll(){  
                  return   acc;  
          }  
           
          public   static   void   main(String[]   args){  
                  Test   t   =   new   Test();  
                  Test   back   =   t.getScroll();  
                   
                  System.out.println("haha.");  
          }  
           
          private   class   Scroll   extends   Test{       //   2  
                  private   int   i   =   0;  
                   
                  public   void   setInt(   int   i){  
                          this.i   =   i;  
                  }  
                   
                  public   int   getInt(){  
                          return   i;  
                  }  
          }  
  } 问题点数:100、回复次数:30Top

1 楼helpall(was jl)回复于 2005-06-14 12:42:39 得分 40

1没有static,则每个Test实例都拥有一个acc变量,每个acc变量又是一个Test的子类Scroll的实例,而该实例又拥有一个acc变量,...,最后堆栈溢出.  
  1改为static后,每个Test实例共用一个acc变量.该变量是Test的子类Scroll的实例,而此实例还是共用该acc变量.   换句话说,acc是在类一级的,不是与实例相连的.   在下例中,三个acc都是一个东西:  
      Test   a   =   new   Test();  
      Test   b   =   new   Test();  
        Test.acc   ==   a.acc;   //   true  
        Test.acc   ==   b.acc;   //   true  
  当然,acc是私有的,不能在外部存取.  
  至于2改成static是因为Scroll是内部类,当1要用static存取时,2一定要用static定义.如果Scroll放在类的外部就可不必用static.Top

2 楼cat_871017(零下九度)回复于 2005-06-14 14:19:33 得分 10

上面这位大哥讲的实在是太详细了,我没什么可说的了  
  那就再讲的"通俗"一点吧  
  因为jvm为子类分配内存的时候是这样的:它先找到一块内存区域存放其父类的相关信息,然后接下来才是子类增加或修改的信息.比如说一   A继承B,那么A的内存里面其实有一块存着B.  
   
  而你的这个程序把一个子类作为父类的内部类,这样父类的内存里要分配一块给子类,而子类又要存放一个父类,这样无限嵌套循环,最后导致溢出了.  
   
  改为static   就好了,因为在嵌套时无论怎么样也只会产生一个内部类的实例,所以就终止了上面那种循环.  
   
  Top

3 楼Sanco(十扇门)回复于 2005-06-14 19:48:27 得分 0

就算   Scroll   不扩展   Test   类   ,程序同样会溢出。同意吗?不信试试Top

4 楼helpall(was jl)回复于 2005-06-14 19:56:49 得分 0

我觉得不应该,   至少下例没有问题.  
  class   Outer   {  
          private     Inner   acc   =   new   Inner();    
   
          public   static   void   main(String[]   args){  
                  Outer   t   =   new   Outer();  
                  System.out.println("haha.");  
          }  
          class   Inner   {   }  
  }Top

5 楼Sanco(十扇门)回复于 2005-06-14 20:08:36 得分 0

我检查下先Top

6 楼Sanco(十扇门)回复于 2005-06-14 20:15:30 得分 0

哦。是我看错了。  
  谢谢   helpall(was   jl)   的指正。  
   
  因为我在代码里有加了个本身的对象实例。  
   
  class   Test{  
      Test   t   =   new   Test();  
      ...  
  }Top

7 楼Sanco(十扇门)回复于 2005-06-14 20:17:39 得分 0

我想其实跟原来的是一个道理。  
   
  t   -〉acc   -〉acc   -〉acc   -〉。。。。Top

8 楼Goldrush(上天有好生之德)回复于 2005-06-15 01:34:04 得分 0

dingTop

9 楼Sanco(十扇门)回复于 2005-06-15 12:08:21 得分 0

也就是说   一个类不能拥有   非静态的   本类对象,直接或间接子类对象。  
   
  再回到内部类:静态或非静态内部类中的私有成员都能被外部类所使用(反过来,外部类的私有成员也能被非静态内部类使用),通过反射机制,看到内部类有个指向外部类对象的this$0隐式指针,然而外部类却没有指向内部类的指针,?那外部类是怎么访问到内部类的呢??Top

10 楼helpall(was jl)回复于 2005-06-15 20:29:05 得分 0

"也就是说   一个类不能拥有   非静态的   本类对象,直接或间接子类对象。"--------好象不对,见下例  
  class   Outer   {  
      public   Outer   o;  
   
      public   static   void   main(String[]   args){  
                  Outer   t   =   new   Outer();  
                  Outer   t1   =   new   Outer();  
                  t.o   =   t1;  
                  System.out.println("haha.");  
      }  
  }Top

11 楼Sanco(十扇门)回复于 2005-06-15 20:59:33 得分 0

你所说的   public   Outer   o;    
  o   只是变量而已,它并没有被实例化,也就是说它还没指向一个对象。  
   
  换成     public   Outer   o   =   new   Outer();   试试。将出现Overflow  
  Top

12 楼faen(发恩)回复于 2005-06-15 21:51:46 得分 0

呵呵,学习了Top

13 楼helpall(was jl)回复于 2005-06-15 22:59:42 得分 0

Sorry,   there's   no   Chinese   input   software   available   here.  
   
  Please   look   into   main().    
      t.o   =   t1;  
  This   statement   makes   t   owns   a   non-static   object   t1   of   same   class.  
   
  I   can   understand   "public   Outer   o   =   new   Outer();   "   throws   Exception.   But   the   statement,"一个类不能拥有非静态的本类对象,直接或间接子类对象。",   is   incorrect.   Think   about   a   Tree-Node   example,   it's   very   common   that   a   Node   owns   parent   and   children,   which   are   non-static.Top

14 楼laughsmile(海边的星空)回复于 2005-06-16 11:18:46 得分 40

1.那外部类是怎么访问到内部类的呢??  
  外部类访问内部类的方法与访问本类中的复合类相同,也是把它当作自己的一个成员.  
  eg:  
  class   A   {  
      class   B{  
          class   C{  
              void   doit(){}  
          }  
      }  
  }  
  class   SeeResult{  
      public   static   void   main(String[]   args){  
            A.B.C   c   =   ((new   A()).new   B()).new   C();  
            c.doit();  
      }  
  }  
  2.   一个类不能拥有   非静态的   本类对象,直接或间接子类对象  
  其实这个原理跟递归是一样的,Tree-Node   example就是一种递归,如果递归的时候没有退出条件,那当然是stack   overflow."一个类不能拥有   非静态的   本类对象,直接或间接子类对象"这种说法就相当于说不能用递归.其实这还是可以使用的,只是要设置好退出条件.Top

15 楼helpall(was jl)回复于 2005-06-16 11:28:38 得分 0

严重同意laughsmile(海边的星空).  
  这一层意思讲得棒极了.要分的话我就另开贴给分.Top

16 楼Sanco(十扇门)回复于 2005-06-16 21:01:55 得分 0

谢谢各位。  
  谢谢helpall(was   jl)     和   laughsmile(海边的星空)    
   
  看这样说怎样:一个类的成员,不能是非静态的(本类或者直接或间接子类的)实例,但可以是静态或非静态的指向本类或其它任何类的指针变量。  
   
  有关内部类到外部类,然后又到超类和接口的所有问题,都是由于本人想实现java中对象应用sizeof方法而来,其实有一种比较简单的方法,不停的实例化对象,然后看用了多少内存(我好像讲的太简单了^-^)。  
  但这种方法在很多场合都不很实用(特别是小内存,图形对象来讲),而且对理解对象的实现机制也没什么帮助。所以参考了网络上广为流传的另一种方法,相信大家都耳熟能详了。  
   
  目前还没什么进展,文章写得太涩,所以一时间弄得有点晕。  
   
  Top

17 楼nimifeng(学海无涯.......苦作舟....理解是美!!!Mars.Neil)回复于 2005-06-16 21:48:09 得分 0

学习..帮顶.Top

18 楼helpall(was jl)回复于 2005-06-16 23:09:40 得分 0

There's   no   指针   concept   in   java.   指针   concept   in   java   is   called   reference.   The   difference   between   a   实例   and   a   reference   is   that   a   实例   is   an   initialized   reference.  
   
  I   still   don't   like   the   statement   you   made.   :-)   The   important   thing   is   that   you   can   understand   the   concept.   Sometime   when   a   statement   is   made,   the   principle   is   twisted.  
   
  People   will   get   confused   when   they   see   you   talk   about   指针变量   in   java,   unless   you   want   C++   users   to   read   it.Top

19 楼zhoulinjulian()回复于 2005-06-17 00:24:46 得分 0

又学到东西了,i   love   csdn!Top

20 楼zhaoce(朋苍.月友)回复于 2005-06-17 09:20:07 得分 0

看这样说怎样:一个类的成员,不能是非静态的(本类或者直接或间接子类的)实例,但可以是静态或非静态的指向本类或其它任何类的指针变量。  
  -------------------------------------------------  
  怎么不行?  
  给一个idea中缺省的单子模式  
  不是不能定义自己一个实例,关键是你要限制他的递归操作  
  不能无限制地递归下去  
   
  public   class   T   {  
          private   static   T   ourInstance   =   new   T();  
   
          public   static   T   getInstance()   {  
                  return   ourInstance;  
          }  
   
          private   T()   {  
          }  
  }  
  Top

21 楼zhaoce(朋苍.月友)回复于 2005-06-17 09:22:49 得分 0

不好意思,看错了  
  前面说错了Top

22 楼zhaoce(朋苍.月友)回复于 2005-06-17 09:32:34 得分 10

这下可以了,写了一个新的例子,调试通过  
  前面例子写得不好,不要意思^_^  
   
  public   class   T   {  
          int   i=0;  
          private   T   ourInstance   ;  
   
          public   T   getInstance()   {  
   
                  return   this.ourInstance;  
   
          }  
   
          private   T(int   i)   {  
                  this.i=i;  
                  if(i==0){  
                          i++;  
                          this.ourInstance=   new   T(i);  
                          this.ourInstance.i++;  
                  }  
                  else{  
                  }  
          }  
   
          public   static   void   main(String[]   args){  
                  T   t=new   T(0);  
          }  
  }  
  Top

23 楼laughsmile(海边的星空)回复于 2005-06-17 11:29:44 得分 0

to   helpall(was   jl)  
  谢谢夸奖,呵呵,如要给我分,那当然是多么多么感谢哦。  
  to   Sanco   (God   of   Tmac)    
  给你介绍一个sizeof程序  
  public   class   Sizeof  
  {  
          public   static   void   main   (String   []   args)   throws   Exception  
          {  
                  //   Warm   up   all   classes/methods   we   will   use  
                  runGC   ();  
                  usedMemory   ();  
   
                  //   Array   to   keep   strong   references   to   allocated   objects  
                  final   int   count   =   100000;  
                  Object   []   objects   =   new   Object   [count];  
                  long   heap1   =   0;  
   
                  //   Allocate   count+1   objects,   discard   the   first   one  
                  for   (int   i   =   -1;   i   <   count;   ++   i)  
                  {  
                          Object   object   =   null;  
                           
                          /*   Instantiate   your   data   here   and   assign   it   to   object*/                          
                          //object   =   new   Object   ();  
                          object   =   new   Integer   (i);              
                          //object   =   new   Long   (i);                
                          //object   =   new   String   ();  
                          //object   =   new   Byte(   (byte)   0);          
                          //object   =   new   Float(   0.2f);                  
                          //object   =   new   Double(   0);                  
                          if   (i   >=   0)  
                                  objects   [i]   =   object;  
                          else  
                          {  
                                  object   =   null;   //   Discard   the   warm   up   object  
                                  runGC   ();  
                                  heap1   =   usedMemory();   //   Take   a   before   heap   snapshot  
                          }  
                  }  
   
                  runGC   ();  
                  long   heap2   =   usedMemory   ();   //   Take   an   after   heap   snapshot:  
                   
                  final   int   size   =   (int)Math.round   (   ((double)(heap2   -   heap1))   /count);  
                  System.out.println   ("'before'   heap:   "   +   heap1   +  
                                                          ",   'after'   heap:   "   +   heap2);  
                  System.out.println   ("heap   delta:   "   +   (heap2   -   heap1)   +  
                          ",   {"   +   objects   [0].getClass   ()   +   "}   size   =   "   +   size   +   "   bytes");  
   
                  for   (int   i   =   0;   i   <   count;   ++   i)   objects   [i]   =   null;  
                  objects   =   null;  
          }  
          private   static   void   runGC   ()   throws   Exception  
          {  
                  //   It   helps   to   call   Runtime.gc()  
                  //   using   several   method   calls:  
                  for   (int   r   =   0;   r   <   4;   ++   r)   _runGC   ();  
          }  
          private   static   void   _runGC   ()   throws   Exception  
          {  
                  long   usedMem1   =   usedMemory   (),   usedMem2   =   Long.MAX_VALUE;  
                  for   (int   i   =   0;   (usedMem1   <   usedMem2)   &&   (i   <   500);   ++   i)  
                  {  
                          s_runtime.runFinalization   ();  
                          s_runtime.gc   ();  
                          Thread.yield   ();  
                           
                          usedMem2   =   usedMem1;  
                          usedMem1   =   usedMemory   ();  
                  }  
          }  
          private   static   long   usedMemory   ()  
          {  
                  return   s_runtime.totalMemory   ()   -   s_runtime.freeMemory   ();  
          }  
          private   static   final   Runtime   s_runtime   =   Runtime.getRuntime   ();  
  }   //   End   of   class  
  Top

24 楼helpall(was jl)回复于 2005-06-17 19:46:13 得分 0

laughsmile(海边的星空),请到  
        http://community.csdn.net/Expert/topic/4090/4090085.xml?temp=.1563837  
  接分.Top

25 楼Sanco(十扇门)回复于 2005-06-18 16:16:54 得分 0

非常感谢   各位的热心,特别是   laughsmile(海边的星空),helpall(was   jl)   两位的激烈讨论。  
  我想也该结贴了。  
   
  to   laughsmile(海边的星空):  
  谢谢你最后给的例子,这个例子得到的是对象的精确的size,耗的内存比较大,并且不太适合小内存容量的图形对象。  
  其实有另一种方法,通过分析对象的继承关系来得到对象的size的近似值。方法在下面网址:  
  http://www.javaworld.com/javaworld/javaqa/2003-12/02-qa-1226-sizeof.html(要是有精炼的语句可以概括这种方法,一定发消息给我,我一定另开贴给分。)  
   
  to   helpall(was   jl):  
  谢谢你的一些概念性的讲解。虽然我仍然将java中的变量用c中的指针来理解(希望我的方式没有误人子弟)。  
  Top

26 楼lvcheng606717(旅程)回复于 2005-06-19 12:26:14 得分 0

标记学习Top

27 楼wtobias(猪猪)回复于 2005-06-30 19:57:26 得分 0

xuexiTop

28 楼interhanchi(on the Java Road)回复于 2005-07-17 02:00:26 得分 0

markTop

29 楼songsong1982(松松)回复于 2005-09-01 14:33:19 得分 0

学习学习  
  Top

30 楼cyxlsm()回复于 2005-09-06 15:15:52 得分 0

static  
  使用static关键字,可以指定一个成员变量为一个类变量或者指定方法为类方法,类方法不能访问实例变量,除非方法先创建类的一个实例并且通过它来访问变量。实例成员和类成员之间的另外一个差别是类成员可以从类本身进行访问。你不必实例化类来访问它的类成员。  
   
  static方法不用创建对象就能访问,仍能访问调用一个static方法  
  原因就是它是类方法,当然不用创建对象就能被访问  
  注意:类方法与实例方法的区别  
  类名+方法  
   
  Top

相关问题

  • 讨论TStringGrid类
  • 小问题:有关JAVA文件名和类名之间的关系?在线讨论,马上结帖!!
  • 讨论一下供求关系
  • 讨论:JDBC中Connection,Statement,ResultSet的关系?
  • [请讨论] FAQ分类
  • 大家讨论一下.Net 和COM+ 之间的关系好吗?
  • 讨论WEB编程高手与JAVASCRIPT高手的关系!!
  • 大家讨论一下客户关系管理软件
  • 讨论关于数据库表的关系问题
  • 网页设计和编码的关系,大家讨论一下

关键词

  • 指针
  • 内存
  • 子类
  • 类
  • 实例
  • 本类
  • acc
  • 变量
  • ourinstance
  • 递归

得分解答快速导航

  • 帖主:Sanco
  • helpall
  • cat_871017
  • laughsmile
  • zhaoce

相关链接

  • CSDN Java频道
  • Java类图书
  • Java类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo