随笔 - 63  文章 - 0  trackbacks - 0
<2009年4月>
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789

常用链接

留言簿(2)

随笔分类

随笔档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜

内部类:定义在其他类里面的类。
使用内部类的理由:
1.内部类方法能够访问外部类的任何数据成员包括私有成员。
2.对同一个包的其他类,内部类是不可见的。
3.匿名内部类能够方便的定义回调而不用写太多方法。

非静态内部类没有默认的构造函数,非静态内部类的构造函数都有一个外围类对象的引用。
内部类的特殊语法规则:
1.相对内部类,引用其外部类隐式对象的形式:OuterClass.this
2.调用内部类的构造函数:outerObject.new InnerClass(construction parameters);
3.外部类外面引用内部类:OuterClass.InnerClass

内部类是一种编译器现象与虚拟机无关。编译器将内部类翻译为用$分隔外部类名和内部类名的常规类文件,虚拟机对此并无所知。
使用javap -private OuterClass$InnerClass。javap这个工具确实挺不错的,对分析字节码和源码都有很大的帮助。
可以看出详细的内部类源码清单,其中包括了编译器自动添加的部分:
public class Outer
{
 public class Inner
 {
 }
}
当内部类是非静态内部类时相应的内部类的详细源码如下:
Compiled from "Outer.java"
public class Outer$Inner extends java.lang.Object{
    final Outer this$0;  //编译器自动在内部类里面添加了指向外部类对象的引用
    public Outer$Inner(Outer);  //内部类的构造函数默认有一个外部类对象作为参数。
}

当内部类是静态内部类时:
Compiled from "Outer.java"
public class Outer$Inner extends java.lang.Object{
    public Outer$Inner(); //没有了对外部类对象的引用
}


如下代码模拟了上面内部类的情形唯一不同的是这里的Inner没有访问Outer私有数据的权限:
class Outer{
   Inner in = new Inner(this);
}

class Inner{
   public Inner(Outer outer){
      this.outer = outer;
   }
  
   private Outer outer;
}

 

//那么权限是如何控制的呢?当内部类中的方法访问到外部类的私有数据时(注意如果内部类没有方法去访问外部类的私有数据不会生成该静态方法static int access$000(Outer);)
public class Outer
{
 private int i;
 public void methodOne()
 {
 }

 class Inner
 {
  public void print(){
   System.out.println(Outer.this.i);
  }
 }
}

相应的外部类详细源码如下:
public class Outer
{
   public Outer();

   public void methodOne();
   static int access$000(Outer); //由编译器合成的用于内部类对外部类进行特殊访问权限的控制:这也是
                                //为什么内部类能够访问外部类中的私有数据的原因。
   private int i;
}

内部类访问外部类的private数据的这种方式很可能导致危险,虽然access$000不是一个合法的Java方法名,但是熟悉class文件结构的黑客可以使用十六进制编辑器轻松创建一个用虚拟机指令调用那个方法的类文件。由于隐秘的访问方法需要拥有包可见性,所以攻击代码需要与被攻击类放在同一个包中。总之,如果内部类访问了外部类的私有数据域,就有可能通过附加在外部类所在包中的其他类访问私有数据。

局部内部类:定义在方法之中,因此局部类没有public和private修饰符。对外界是完全隐藏的。
局部类不仅能够访问外部类,还能访问方法中的局部变量(或方法的参数)。不过那些局部变量要声明为final的。


匿名内部类:用外部类+$+数字的形式表示。一个外部类中有多个匿名内部类时,其生成的class文件对应有Outer$(1、2、3)的形式表示。注意到该匿名内部类是final的。
final class Outer$1
{
   Outer$1(Outer);

   public void method();

   final Outer this$0;
}

嵌套类:当内部类不需要访问外部类的数据成员时应该使用嵌套类。注意只有内部类可以声明为static的其他不行。
在接口中声明的内部类自动转换为public static的,在接口中定义的成员自动都是public static的。

内部类构造函数的可见性与其类的可见性相同。

 

posted on 2009-04-16 14:06 lanxin1020 阅读(140) 评论(0)  编辑  收藏 所属分类: j2se

只有注册用户登录后才能发表评论。


网站导航: