Java之匿名类讲解

Posted lijingran

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java之匿名类讲解相关的知识,希望对你有一定的参考价值。

参考https://blog.csdn.net/jiaotuwoaini/article/details/51542059

匿名类,正如名字一样在java中没有名字标识的类,当然了编译后还是会安排一个名字的。

下面是一个关于匿名类的简单例子:

public class Client {  
  
    public static void main(String[] args) throws InterruptedException {  
        Thread t=new Thread(new Runnable() {  
              
            @Override  
            public void run() {  
                System.out.println("hello,dusk!");  
                  
            }  
        });  
        t.start();  
    }  
  
}  

Java语言规范上是这么描述匿名类的:

匿名类的声明:

匿名类的声明是由java编译器自动派生自一个类实例创建表达式。

匿名类永远不能是抽象的。

匿名类总是隐式的final。

匿名类总是一个内部类;并且不能是static的。

匿名构造函数:

匿名类不能有显式声明的构造函数。相反的,Java编译器必须为这个匿名类自动提供一个匿名构造函数。匿名类C继承于父类S那么匿名构造函数是下面的形式:

  • 如果S不是一个内部类或者S是一个静态上下文中的局部类,那么这个匿名构造函数有一个形参为每一个在C的类实例创建表达式中的实际参数。

类的实例创建表达式的实际参数用来确定S的一个构造函数cs,使用方法调用相同的规则。

每一个匿名构造函数的形参必须和cs中的相关形参一致。

这个构造函数中显式的包括super(...)构造函数调用,这个实际参数是构造函数的形参,按它们声明的顺序。 

  • 否则,C的构造函数第一个形参描述了这个值,直接包围实例i相对于S。参数的类型是S的class类型。

构造函数有一个额外的形参为每一个类实例创建语句声明在匿名类中的实际参数。第n个形参和第n-1个实际参数相关。

类的实例创建表达式的实际参数用来确定S的一个构造函数cs,使用方法调用相同的规则。

每一个匿名构造函数的形参必须和cs中的相关形参一致。

这个构造函数中显式的包括super(...)构造函数调用,这个实际参数是构造函数的形参,按它们声明的顺序。

在所有的情况下,匿名构造函数的throws语句必须列出所有的检查异常,包括父类构造函数显式调用语句抛出的和匿名类的实例初始化或者变量初始化抛出的异常。

注意:匿名构造函数的签名涉及到了一个不可达类型是可能的(例如,出现在父类构造函数中的类型),这不会导致任何编译时和运行时错误。

实际使用中我们只需注意这几点儿:

      1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
      2、匿名内部类中是不能定义构造函数的。
      3、匿名内部类中不能存在任何的静态成员变量和静态方法。
      4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
      5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

编译时的命名规则:

  • 内部类的class文件命名是:主类+$+内部类名
  • 匿名类的class文件命名是:主类+$+(1,2,3....)

定义一个场景:

package com.dusk.anonymous;  
  
public class AnonymousClassTest {  
    private Runnable r1=new Runnable() {  
          
        @Override  
        public void run() {  
            System.out.println(1);  
        }  
    };  
    public void method1(){  
        Runnable r2=new Runnable() {  
              
            @Override  
            public void run() {  
                System.out.println(2);  
            }  
        };  
    }  
    public static void main(String[] args) {  
            Runnable r3=new Runnable() {  
                  
                @Override  
                public void run() {  
                    System.out.println(3);  
                }  
            };  
    }  
}  
 

从代码中我们可以看出定义了三个匿名类:

技术分享图片

我们反编译出来:

package com.dusk.anonymous;  
  
import java.io.PrintStream;  
  
class AnonymousClassTest$1  
  implements Runnable  
{  
  AnonymousClassTest$1(AnonymousClassTest paramAnonymousClassTest) {}  
    
  public void run()  
  {  
    System.out.println(1);  
  }  
}  

package com.dusk.anonymous;  
  
import java.io.PrintStream;  
  
class AnonymousClassTest$2  
  implements Runnable  
{  
  AnonymousClassTest$2(AnonymousClassTest paramAnonymousClassTest) {}  
    
  public void run()  
  {  
    System.out.println(2);  
  }  
}  

package com.dusk.anonymous;  
  
import java.io.PrintStream;  
  
class AnonymousClassTest$3  
  implements Runnable  
{  
  public void run()  
  {  
    System.out.println(3);  
  }  
}  
我们可以看出匿名类的名字中的数字和他们在代码中出现的位置一模一样。




以上是关于Java之匿名类讲解的主要内容,如果未能解决你的问题,请参考以下文章

2020/7/8 JAVA总结之:匿名对象/内部类/包的声明与访问/访问修饰符/代码块

Think in java读书笔记之:java匿名内部类的继承和覆盖

Java之局部内部类和匿名内部类的区别详解(附源码)

详细讲解 —— 多线程初阶认识线程(Java EE初阶)

Java学习笔记之二十六深入理解Java匿名内部类

Java基础学习笔记十 Java基础语法之finalstatic匿名对象内部类