美文网首页Javajava
浅谈Java的匿名类

浅谈Java的匿名类

作者: whitejava | 来源:发表于2016-10-04 11:19 被阅读4632次

在实际的项目中看到一个很奇怪的现象,Java可以直接new一个接口,然后在new里面粗暴的加入实现代码。就像下面这样。那么问题来了,new出来的对象没有实际的类作为载体,这不是很奇怪吗?

思考以下代码的输出是什么?

Runnable x = new Runnable() {  
    @Override  
    public void run() {  
        System.out.println(this.getClass());  
    }  
};  
x.run();  

实际答案是出现xxxx$1这样一个类名,它是编译器给定的名称。

匿名类

匿名类相当于在定义类的同时再新建这个类的实例。我们来看看匿名类的编译结果。

这个类的代码如下:

public class Test {  
  public void test() {  
    Runnable r = new Runnable(){  
      @Override  
      public void run(){  
        System.out.println("hello");  
      }  
    };  
  }  
}  

来看看它的编译结果,通过javap反向编译Test.class,得到的结果如下:

SourceFile: "Test.java"  
EnclosingMethod: #20.#21                // Test.test  
InnerClasses:  
     #6; //class Test$1  

发现了一个字段叫EnclosingMethod,说明这个类是定义在Test.test方法下的。那现在有个问题,如果有两个test方法,会出现什么呢?

原来是旁边这个注释不太准确,实际上会包含函数签名的。请看Constant Pool部分,这里的#21指向了这个函数签名。

#21 = NameAndType        #34:#16        // test:()V  

匿名类的语法

这里举一个简单的例子:

Runnable hello = new Runnable() {  
    public void run() {  
        System.out.println("hello");  
    }  
};  

一个匿名类由以下几个部分组成:

  1. new操作符
  2. Runnable:接口名称。这里还可以填写抽象类、普通类的名称。
  3. ():这个括号表示构造函数的参数列表。由于Runnable是一个接口,没有构造函数,所以这里填一个空的括号表示没有参数。
  4. {...}:大括号中间的代码表示这个类内部的一些结构。在这里可以定义变量名称、方法。跟普通的类一样。

访问权限

那么匿名内部类能访问哪些东西呢?按照规则,可以访问如下内容:

  1. 访问外层Class里面的字段。
  2. 不能访问外层方法中的本地变量。除非变量是final。
  3. 如果内部类的名称和外面能访问的名称相同,则会把名称覆盖掉。
public class A {  
    private int foo;  
    public void test() {  
        Runnable r = new Runnable() {  
            System.out.println(foo);  
        };  
    }  
}  

匿名类里面不可以有的东西:
1.不能定义静态初始化代码块(Static Initializer)。比如下面的代码是不符合语法的:

public class A {  
    public void test() {  
        Runnable r = new Runnable() {  
            static { System.out.println("hello"); }  
        };  
    }  
}  

2.不能在匿名类里面定义接口。

比如:

public class A {  
    public void test() {  
        Runnable r = new Runnable() {  
            public interface Hello { };  
        };  
    }  
}  

和上面一样,也是为了语义的清晰。interface只能定义静态的。

3.不能在匿名类中定义构造函数。

public class A {  
    public void test() {  
        Runnable r = new Runnable() {  
            public Runnable() { }  
        };  
    }  
} 

因为匿名类没有名字,而构造函数需要把类名作为方法名才能看成构造函数。
匿名类中可以包含的东西有:

  1. 字段
  2. 方法
  3. 实例初始化代码
  4. 本地类

为什么不能定义静态初始化代码

事实上,内部类中不能定义任何静态的东西。

关键字:Inner class cannot have static declarations

参考资料:http://stackoverflow.com/questions/975134/why-cant-we-have-static-method-in-a-non-static-inner-class

StackOverFlow上看起来有一种解释如下。

首先来看一个内部类。

public class A {  
  public class B {  
  }  
}  

它编译之后,会变成下面这种含义:

public class A {  
  public static class B {  
    private final A parent;  
    public B(A parent) {  
      this.parent = parent;  
    }  
  }  
} 

所以,按照这么说,内部类就是一种语法糖。当我们定义静态变量时,就会产生下面这种歧义。下面的代码看起来没什么问题。

public class A {  
  private int a;  
  public class B {  
    public static void test() {  
      a = 1;  
    }  
  }  
}  

但是编译之后,问题就来了。

public class A {  
  private int a;  
  public static class B {  
    private final A parent;  
    public B (A parent) { this.parent = parent; }  
    public static void test() {  
      parent.a = 1; // 这里有语法错误  
    }  
  }  
}  

所以,归根结底,Java为了保持清晰的语法,不允许这种有歧义的语法存在。

相关文章

  • 浅谈Java的匿名类

    在实际的项目中看到一个很奇怪的现象,Java可以直接new一个接口,然后在new里面粗暴的加入实现代码。就像下面这...

  • Java匿名类

    实例1:不使用匿名内部类来实现抽象方法 实例2:匿名内部类的基本实现 实例3:在接口上使用匿名内部类

  • 匿名类

    匿名类: 匿名类,就是没有名称的类,其名称由Java编译器给出,一般是形如:外部类名称+$+匿名类顺序,没有名称也...

  • java8官方文档—Lambda表达式

    声明:本文翻译自The Java™ Tutorials(官方文档) 简述 匿名类有一个问题,如果匿名类的实现非常简...

  • 知识点总结

    1. java: * 集合 * 内部类,匿名类,静态类 * 抽象类,接口区别 * 线程池 * ...

  • C++11新特性--lambda

    匿名函数--lambda函数     匿名函数或者匿名类这种语法在其他语言(如lisp,java中)早有应用。在C...

  • JAVA NIO之浅谈内存映射文件原理与DirectMemory

    转自 [Java][IO]JAVA NIO之浅谈内存映射文件原理与DirectMemory Java类库中的NIO...

  • java内部匿名类

    前言:java基础的编写类的时候,会觉得很匿名内部类很神秘.普通的java文件会被编译成class,那内部类和匿名...

  • Java8笔记(3)

    Java8笔记(3) 从匿名类到 Lambda 表达式的转换 例子: 创建Runnable对象的匿名类 但是某些情...

  • kotlin中sam(函数式接口)

    用lambda表达式去表示java中的匿名类实例在使用java去给一个按钮设置监听我们通常会通过创建匿名类实例,如...

网友评论

    本文标题:浅谈Java的匿名类

    本文链接:https://www.haomeiwen.com/subject/repitttx.html