简洁明了:Java的匿名内部类

一 点睛

匿名内部类适合创建那种只需要一次使用的类,定义匿名内部类的语法格式如下:

new 父类构造器(实参列表) | 实现接口()

{

      //匿名内部类的类体部分

}

从上面的定义可以看出,匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口。

两条规则。

  • 匿名内部类不能是抽象类。

  • 匿名内部类不能定义构造器。由于匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以初始化块,可以通过初始化块来完成构造器需要完成的工作。

二 实战

1 点睛

最常用的创建匿名内部类的方式是创建某个接口类型的对象。

2 代码

interface Product
{
   public double getPrice();
   public String getName();
}
public class AnonymousTest
{
   public void test(Product p)
   {
      System.out.println("购买了一个" + p.getName()
         + ",花掉了" + p.getPrice());
   }
   public static void main(String[] args)
   {
      AnonymousTest ta = new AnonymousTest();
      // 调用test()方法时,需要传入一个Product参数,
      // 此处传入其匿名内部类的实例
      ta.test(new Product()
      {
         public double getPrice()
         {
            return 567.8;
         }
         public String getName()
         {
            return "AGP显卡";
         }
      });
   }
}

3 运行

<p>购买了一个AGP显卡,花掉了567.8</p>

4 说明

定义匿名内部类无须class关键字,而是在定义匿名内部类时直接生成该匿名内部类的对象。

由于匿名内部类不能是抽象类,所以匿名内部类必须实现它的抽象父类或接口里包含的所有抽象方法。

三 实战

1 点睛

当通过接口来创建匿名内部类时,匿名内部类不能显示创建构造器,因此匿名内部类里只有一个隐式的无参构造器,故new接口名后的括号里不能传入参数值。

如果通过继承父类来创建匿名内部类时,匿名内部类将拥有和父类相似的构造器,此处的相似指的是拥有相同的形参列表。

2 代码

abstract class Device
{
   private String name;
   public abstract double getPrice();
   public Device(){}
   public Device(String name)
   {
      this.name = name;
   }
   // 此处省略了name的setter和getter方法
   public void setName(String name)
   {
      this.name = name;
   }
   public String getName()
   {
      return this.name;
   }
}
public class AnonymousInner
{
   public void test(Device d)
   {
      System.out.println("购买了一个" + d.getName()
         + ",花掉了" + d.getPrice());
   }
   public static void main(String[] args)
   {
      AnonymousInner ai = new AnonymousInner();
      // 调用有参数的构造器创建Device匿名实现类的对象
      ai.test(new Device("电子示波器")
      {
         public double getPrice()
         {
            return 67.8;
         }
      });
      // 调用无参数的构造器创建Device匿名实现类的对象
      Device d = new Device()
      {
         // 初始化块
         {
            System.out.println("匿名内部类的初始化块...");
         }
         // 实现抽象方法
         public double getPrice()
         {
            return 56.2;
         }
         // 重写父类的实例方法
         public String getName()
         {
            return "键盘";
         }
      };
      ai.test(d);
   }
}

3 运行

购买了一个电子示波器,花掉了67.8
匿名内部类的初始化块...
购买了一个键盘,花掉了56.2

当创建以Device为父类的匿名内部类时,既可以传入参数,代表调用父类带参数的构造器;也可以不传入参数,代表调用父类无参数的构造器。

当创建匿名内部类时,必须实现接口或抽象父类里的所有抽象方法。如果有需要,也可以重写父类中的普通方法。

四 实战

1 点睛

在Java 8之前,Java要求被局部内部类、匿名内部类访问的局部变量必须使用final修饰,从Java 8开始这个限制取消了,Java 8更加智能:如果局部变量被匿名内部类访问,那么该局部变量相对于自动使用了final修饰。

2 代码

interface A
{
   void test();
}
public class ATest
{
   public static void main(String[] args)
   {
      int age = 8;     // ①
      // 下面代码将会导致编译错误
      // 由于age局部变量被匿名内部类访问了,因此age相当于被final修饰了
      //age = 2;
      A a = new A()
      {
         public void test()
         {
            // 在Java 8以前下面语句将提示错误:age必须使用final修饰
            // 从Java 8开始,匿名内部类、局部内部类允许访问非final的局部变量
            System.out.println(age);
         }
      };
      a.test();
   }
}

3 结果

<p>
8</p>

4 说明

Java 8将这个功能称为“effectively final”,它的意思是对于被匿名内部类访问的局部变量,可以用final修饰,也可以不用final修饰,但必须按照有final修饰的方式来使用——也就是一次赋值后,以后不能重新赋值。

发布了70 篇原创文章 · 获赞 134 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_39380155/article/details/105673935
今日推荐