匿名内部类详解

匿名内部类

匿名内部类就是没有名字的内部类;


注意:

匿名内部类不能定义任何静态成员、方法。

匿名内部类中的方法不能是抽象的;

匿名内部类必须实现接口或抽象父类的所有抽象方法。

匿名内部类访问的外部类成员变量或成员方法必须用static修饰;


代码:

接口

public interface Inner {
    public String say();
}

抽象类

public abstract class Inner1 implements Inner {
}

普通类

public class Inner2 implements Inner {
    public String say() {
        return "this is Inner2";
    }
}

外部类

public class Outer {

    public static String s1 = "this is s1 in Outer";
    public static String s2 = "this is s2 in Outer";
    private static String s3 = "this is s3 in Outer";

    public void method1(Inner inner) {
        System.out.println(inner.say());
    }

    private static String method2() {
        return "this is method2 in Outer";
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        // 测试1,Inner为接口
        outer.method1(new Inner() {
            String s1 = "this is s1 in Inner";

            public String say() {
                // 外部类和匿名函数类中有同名变量s1
                return s1;
            }
        });
        // 测试2,Inner1为抽象类
        outer.method1(new Inner1() {
            String s2 = "this is s2 in Inner1";

            public String say() {
                // 外部类和匿名函数类中有同名变量s2
                return Outer.s2;
            }
        });
        // 测试3,Inner2为普通类
        outer.method1(new Inner2() {
            public String say() {
                // 访问外部类私有变量s3
                return s3;
            }
        });
        // 测试4,Inner2为普通类
        outer.method1(new Inner2() {
            public String say() {
                // 访问外部类私有方法method1()
                return method2();
            }
        });
    }
}

打印:

this is s1 in Inner
this is s2 in Outer
this is s3 in Outer
this is method2 in Outer

分析:

编译后自动生成四个文件:Outer$1.class、Outer$2.class、Outer$3.class、Outer$4.class。

Outer.class反编译(属性值、方法内容略)

public class jichu.Outer {
  public static java.lang.String s1;
  public static java.lang.String s2;
  private static java.lang.String s3;
  static {};
  public jichu.Outer();
  public void method1(jichu.Inner);
  private static java.lang.String method2();
  public static void main(java.lang.String[]);
  static java.lang.String access$0();
  static java.lang.String access$1();
}

Outer$1.class反编译(经优化、调整)

class Outer$1
  implements Inner
{
  String s1 = "this is s1 in Inner";
  
  public String say()
  {
    return this.s1;
  }
}

Outer$2.class反编译(经优化、调整)

class Outer$2
  extends Inner1
{
  String s2 = "this is s2 in Inner1";
  
  public String say()
  {
    return Outer.s2;
  }
}

Outer$3.class反编译(经优化、调整)

class Outer$3
  extends Inner2
{
  public String say()
  {
    return Outer.access$0();
  }
}

Outer$4.class反编译(经优化、调整)

class Outer$4
  extends Inner2
{
  public String say()
  {
    return Outer.access$1();
  }
}

1、匿名内部类因为没有类名,可知匿名内部类不能定义构造器

2、因为在创建匿名内部类的时候,会立即创建它的实例,可知匿名内部类不能是抽象类,必须实现接口或抽象父类的所有抽象方法

3、匿名内部类会继承一个父类(有且只有一个)或实现一个接口(有且只有一个),实现父类或接口中所有抽象方法,可以改写父类中的方法,添加自定义方法。

5、当匿名内部类和外部类有同名变量(方法)时,默认访问的是匿名内部类的变量(方法),要访问外部类的变量(方法)则需要加上外部类的类名。

6、从Outer.class反编译代码中可看出自动生成了两个静态方法:access$0()和access$1(),并在测试3和测试4中通过Outer类名直接调用,这样实现了内部类对外部类私有成员变量和方法的访问。可知内部类可以访问外部类私有变量和方法


疑问

匿名内部类不能含有static的变量和方法。但是测试发现变量可以被static final修饰,为什么?

主要是因为final类型在编译期间jvm有优化,常量池会维护这些变量。虽然非静态内部类不能脱离外部类这个上下文实例化,但是常量池使得final变量脱离了类实例化这个条件,编译期间便可确定。


总结

1、匿名内部类不能定义任何静态成员、方法。

2、匿名内部类中的方法不能是抽象的;

3、匿名内部类必须实现接口或抽象父类的所有抽象方法。

4、匿名内部类不能定义构造器;

5、匿名内部类访问的外部类成员变量或成员方法必须用static修饰;

6、内部类可以访问外部类私有变量和方法。
posted @ 2016-11-28 18:10  SQP51312  阅读(39356)  评论(1编辑  收藏