匿名内部类

一、 内部类特性

  1.  内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。
  2.  内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 。
  3.  内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。

二、 匿名内部类

1. 

 

 1 public class Parcel7
 2 {
 3     public Contents contents()
 4     {
 5         return new Contents()
 6         {
 7             private int i = 11;
 8             public int value() { return i; }
 9         };
10     }
11     public static void main(String[] args)
12     {
13         Parcel7 p = new Parcel7();
14         Contents c = p.contents();
15     }
16 }

 

在上述代码中, contents() 方法将返回值的生成与表达这个返回值的类定义结合在一起。另外,这个类是匿名的,它没有名字。

语法:创建一个继承自Contents的匿名类的对象。通过new表达式返回的引用被自动向上转型为对Contents的引用。(向上转型内容参照:https://www.cnblogs.com/Leo-Xia/p/10917614.html

关于分号的说明:在匿名内部类末尾的分号,并不是用来标记此内部类结束的。实际上,它标记的是表达式的结束,只不过这个表达式正巧包含了匿名内部类,因此,这与别的地方使用的分号是一致的。

上述匿名内部类的代码,是下面代码的简化版本:

 1 public class Parcel7
 2 {
 3     public MyContents implements contents
 4     {
 5         private int i = 11;
 6         public int value() { return i; }
 7     }
 8     public Contents contents() { return new MyContents(); }
 9     public static void main(String[] args)
10     {
11         Parcel7 p = new Parcel7();
12         Contents c = p.contents();
13     }
14 }

在这个匿名类中,使用了默认的构造器来生成Contents。

 

2. 下面代码展示了基类需要一个有参数的构造器

 1 public class Wrapping
 2 {
 3     private int i;
 4     public Wrapping(int x) { i = x; }
 5     public int value() { return i; }
 6 }
 7 //////////////////////////////////////////
 8 public class Parcel8
 9 {
10     public Wrapping wrapping(int x)
11     {
12         return new Wrapping(x)
13         {
14             public int value()
15             { 
16                 return super.value() * 47; 
17             }
18         };
19     }
20     public static void main(String[] args)
21     {
22         Parcel8 p = new Parcel8();
23         Contents w = p.wrapping();
24     }
25 }

在该例子中,可以看到Wrapping拥有一个要求传递参数的构造器。

这里是将x传进new Warpping(x)。

在匿名内部类中,只需要简单地传递合适的参数给基类的构造器即可。

 

3. 在匿名内部类定义中,对其进行初始化操作

 1 public class Parcel9
 2 {
 3     public Destination destination(final String dest)
 4     {
 5         return new Destination()
 6         {
 7             private String lable = dest;
 8             public String readLable() { return lable; }
 9         };
10     }
11     public static void main(String[] args)
12     {
13         Parcel9 p = new Parcel9();
14         Destination d = p.destination("Tasmaina");
15     }
16 }

在new Destination()中,使用到了在其外部定义的变量dest,编译器要求我们引用的参数是final的

即: 如果定义一个匿名内部类,并且希望他使用一个在其外部定义的对象,那么编译器会要求其参数引用final的。

 

4. 

如果只是简单的给一个字段赋值,那么3例中的方法是很好的。但是,如果想做一个类似构造器的行为,但是匿名类中不可能有命名构造器(其原因是因为它根本就没有名字)。通过实例初始化,就能够达到为匿名内部类创建一个构造器的效果。具体实例如下:

 1 abstract class Base
 2 {
 3     public Base(int i)
 4     {
 5         System.out.println("Base coustructor. i = " + i);
 6     }
 7     public abstract void f();
 8 }
 9 public class AnonymousConstructor
10 {
11     public static Base getBase(int i)
12     {
13         return new Base(i)
14         {
15             { System.out.println("Inside instance initializer "); }
16             public void f()
17             {
18                 System.out.println("In anonymous f()");
19             }
20         };
21     }
22         public static void main(String[] args)
23         {
24             Base base = getBase(47);
25             base.f();
26         }
27 }

注意: 在此例中,并没有要求变量 i 一定是final的,因为 i 被传递给匿名类的基类的构造器,并没有在匿名类内部被直接使用。

 

5. 下面代码为带实例初始化的形式

 1 public class Parcel10
 2 {
 3     public Destination destination(final String dest, final float price) 
 4     {
 5         return new Destination()
 6         {
 7             private int cost;
 8             {
 9                 cost = Math.round(price);
10                 if(cost > 100)
11                     System.out.println("Over budget");
12             }
13             private String lable = dest;
14             public String readLable() { return lable; }
15         };
16     }
17     public static void main(String[] args)
18     {
19         Parcel10 p = new Parcel10();
20         Destination d = p.destination("Tasmaina", 101.395F);
21     }
22 }

其中 destination 的参数必须是 final 的,因为他们在匿名类中被使用到了。

在实例初始化的内部,有 if 语句,它们不能作为实例初始化动作的一部分。所以对于匿名类而言,实例初始化的实际效果就是构造器。(但是,你不能重载实例初始化方法,所以仅有一个这样的构造器)

 

匿名内部类与正规继承相比是受到限制的,因为匿名内部类既可以扩展类,也可以实现接口,但是不能二者兼备。并且,如果是实现接口,也只能实现一个接口。

 

posted @ 2019-06-03 11:59  小鹏_Leo  阅读(456)  评论(0编辑  收藏  举报