📜  Java中的匿名内部类

📅  最后修改于: 2020-04-06 04:55:50             🧑  作者: Mango

先决条件:Java中的嵌套类
这是一个没有名称的内部类,并且仅为其创建一个对象。当使用某些“额外”(例如类或接口的重载方法)创建对象的实例时,匿名内部类可能很有用,而不必实例化子类。

匿名内部类对于编写图形编程中的侦听器接口的实现类很有用。
匿名内部类主要以两种方式创建:

  • 类(可以是抽象的或具体的)
  • 接口

语法:匿名类表达式的语法类似于构造函数的调用,只是代码块中包含类定义。

// Test可以是interface,abstract/concrete类
Test t = new Test()
{
   // 数据成员和方法
   public void test_method()
   {
      ........
      ........
    }
};

要了解匿名内部类,让我们展示一个简单的程序:

//Java展示匿名内部类
interface Age
{
    int x = 21;
    void getAge();
}
class AnonymousDemo
{
    public static void main(String[] args)
    {
        // Myclass实现了Age接口
        MyClass obj=new MyClass();
        // 调用getage()方法 
        obj.getAge();
    }
}
// Myclass实现了Age接口
class MyClass implements Age
{
    @Override
    public void getAge()
    {
        //打印age
        System.out.print("年龄 "+x);
    }
}

在程序中,使用AgeAget()方法和x = 21创建接口Age。Myclass被编写为Age接口的实现类。正如在Program中所做的那样,无需编写单独的类Myclass。而是直接将Myclass的代码复制到此参数中,如下所示:

Age oj1 = new Age() {
            @Override
            public void getAge() {
                System.out.print("年龄 "+x);
            }
        };

在这里,没有创建Age对象,而是创建了Myclass对象,并将其复制到整个类代码中,如上所示。这仅对于匿名内部类是可能的。这样的类称为“匿名内部类”,因此在这里我们将“ Myclass”称为匿名内部类。
上述程序的匿名内部类版本

//Java程序展示匿名内部类
interface Age
{
    int x = 21;
    void getAge();
}
class AnonymousDemo
{
    public static void main(String[] args) {
        // Myclass是Age接口的隐藏的内部类
        Age oj1 = new Age() {
            @Override
            public void getAge() {
                 // 打印age
                System.out.print("年龄 "+x);
            }
        };
        oj1.getAge();
    }
}

匿名内部类的类型:根据声明和行为,有3种匿名内部类:

    1. 扩展类的匿名内部类:我们可以扩展类的匿名内部类。例如,我们知道可以通过扩展Thread类来创建线程。假设我们需要一个立即线程immediate thread,但是我们不想创建一个始终扩展Thread的类。通过这种匿名内部类,我们可以如下定义一个就绪线程:
      //Java展示创建一个立即线程,使用匿名内部类进行拓展
      class MyThread
      {
          public static void main(String[] args)
          {
              // 使用匿名内部类
              Thread t = new Thread()
              {
                  public void run()
                  {
                      System.out.println("子线程");
                  }
              };
              t.start();
              System.out.println("主线程");
          }
      }

      输出:

      主线程
      子线程
      OR
      子线程
      主线程
    2. 实现接口的匿名内部类:我们也可以使用实现接口的匿名内部类,例如,我们还知道通过实现Runnable接口可以创建线程。在这里,我们使用实现接口的匿名内部类。
      //Java程序定义接口,使用匿名内部类实现接口
      class MyThread
      {
          public static void main(String[] args)
          {
              //使用匿名内部类实现接口Runnable
              Runnable r = new Runnable()
              {
                  public void run()
                  {
                      System.out.println("子线程");
                  }
              };
              Thread t = new Thread(r);
              t.start();
              System.out.println("主线程");
          }
      }

      输出:

      主线程
      子线程
      OR
      子线程
      主线程
      
    3. 定义内部方法/构造函数参数的匿名内部类:方法/构造函数参数的匿名内部类通常在图形用户界面(GUI)应用程序中使用。为了使您熟悉语法,让我们看一下以下程序,该程序使用这种类型的匿名内部类创建线程:
      //Java 定义一个线程,使用匿名内部类
      class MyThread
      {
          public static void main(String[] args)
          {
              // 使用匿名内部类
              Thread t = new Thread(new Runnable()
              {
                  public void run()
                  {
                      System.out.println("子线程");
                  }
              });
              t.start();
              System.out.println("主线程");
          }
      }

      输出:

      主线程
      子线程
      OR
      子线程
      主线程
      

普通/常规类和匿名内部类之间的区别:

  • 普通类可以实现任何数量的接口,但是匿名内部类一次只能实现一个接口。
  • 常规类可以扩展一个类并同时实现任意数量的接口。但是匿名的Inner类可以扩展一个类或可以实现一个接口,但一次不能两者都实现。
  • 对于常规/普通类,我们可以编写任意数量的构造函数,但不能为匿名内部类编写任何构造函数,因为匿名类没有任何名称,并且在定义构造函数类名称和构造函数名称时必须相同。

访问封闭范围的局部变量,以及声明和访问匿名类的成员
与局部类一样,匿名类也可以捕获变量。它们对包含范围的局部变量具有相同的访问权:

  • 匿名类可以访问其封闭类的成员。
  • 匿名类无法在其封闭范围内访问未声明为final或有效地为final的局部变量。
  • 像嵌套类一样,匿名类中的类型声明(例如变量)会掩盖封闭范围内具有相同名称的任何其他声明。

匿名类在成员方面也具有与本地类相同的限制:

  • 我们不能在匿名类中声明静态初始化器或成员接口。
  • 匿名类可以具有静态成员,前提是它们是常量变量。

请注意,您可以在匿名类中声明以下内容:

  • 字段
  • 额外的方法(即使它们未实现任何超类型的方法)
  • 实例初始化器
  • 局部类

但是,不能在匿名类中声明构造函数。