在实际的项目中看到一个很奇怪的现象,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的匿名类的更多相关文章

  1. 浅谈JAVA中“增强”类的某个方法的几个中方法!

    一.继承 使用场景:能够控制这个类的构造的时候,才可以使用继承. 优点:简单容易使用, 缺点:耦合性大大的增强,不利于后期的维护,所以对于继承这种方法,谨慎使用.  代码实现:二.装饰者模式 使用场景 ...

  2. 浅谈java类集框架和数据结构(2)

    继续上一篇浅谈java类集框架和数据结构(1)的内容 上一篇博文简介了java类集框架几大常见集合框架,这一篇博文主要分析一些接口特性以及性能优化. 一:List接口 List是最常见的数据结构了,主 ...

  3. 浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance

    浅谈Java代理一:JDK动态代理-Proxy.newProxyInstance java.lang.reflect.Proxy:该类用于动态生成代理类,只需传入目标接口.目标接口的类加载器以及Inv ...

  4. 浅谈Java的throw与throws

    转载:http://blog.csdn.net/luoweifu/article/details/10721543 我进行了一些加工,不是本人原创但比原博主要更完善~ 浅谈Java异常 以前虽然知道一 ...

  5. 浅谈Java中的equals和==(转)

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...

  6. 浅谈Java中的对象和引用

    浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...

  7. 浅谈Java中的equals和==

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...

  8. 浅谈JAVA集合框架

    浅谈JAVA集合框架 Java提供了数种持有对象的方式,包括语言内置的Array,还有就是utilities中提供的容器类(container classes),又称群集类(collection cl ...

  9. 浅谈java性能分析

    浅谈java性能分析,效能分析 在老师强烈的要求下做了效能分析,对上次写过的词频统计的程序进行分析以及改进. 对于效能分析:我个人很浅显的认为就是程序的运行效率,代码的执行效率等等. java做性能测 ...

随机推荐

  1. 扑面而来的碎片--图片3D炸裂效果初体验

    之前逛园子的时候看到 ChokCoco 的爆炸效果作品:[BOOM]一款有趣的Javascript动画效果 (大神英文有没有拼错呀←.←),觉得蛮有意思的,效果如下: 不过觉得这个爆炸效果还是偏软了一 ...

  2. Visual Studio Code,完美的编辑器

    今日凌晨,微软的文本(代码)编辑器 Visual Studio Code(简称 VS Code),发布了首个正式版,距离首个 beta 版上线时间刚好一年. 在十多年的编程经历中,我使用过非常多的的代 ...

  3. 2000条你应知的WPF小姿势 基础篇<22-27 WPF生命周期, 基础类等>

    端午长假在家陪着女朋友, 幸福感满满,生活对于一只饱经忧患的程序猿来说也是非常重要的,也就暂时没有更新博客.休假结束,回归奋斗的日子了,开始继续更新WPF系列. 在正文开始之前需要介绍一个人:Sean ...

  4. 一缕阳光:DDD(领域驱动设计)应对具体业务场景,如何聚焦 Domain Model(领域模型)?

    写在前面 阅读目录: 问题根源是什么? <领域驱动设计-软件核心复杂性应对之道>分层概念 Repository(仓储)职责所在? Domain Model(领域模型)重新设计 Domain ...

  5. linux笔记

    1 动态查看日志 tail -f filename tail -1000f filename 2 解压当前目录内容为xxx.zip  zip -r xxx.zip ./* 3 查看内存使用情况 fre ...

  6. Web网站中利用JavaScript中ActiveXObject对象获取硬件信息(显示器数量、分辨率)从而进行单双屏跳转

    前言:最近这两天工作上,要实现一个功能,在好友阿聪的帮助下,算是比较好的解决了这个需求. B/S的Web网站,需要实现点击按钮时,根据客户端连接的显示屏(监视器)数量进行,单双屏跳转显示新页面. 由于 ...

  7. Underscore.js

    概述 Underscore.js是一个很精干的库,压缩后只有4KB.它提供了几十种函数式编程的方法,弥补了标准库的不足,大大方便了JavaScript的编程.MVC框架Backbone.js就将这个库 ...

  8. iOS-----正则表达式的基础语法

    正则表达式简单语法总结 一.什么是正则表达式 从概念上来说,正则表达式也是一门小巧而精炼的语言,它可以用来简化检索特定的字符串,替换特定字符等功能,有许多开发语言工具,都内嵌支持正则表达式.那么一个正 ...

  9. Redis数据结构详解(一)

    前言 Redis和Memcached最大的区别,Redis 除啦支持数据持久化之外,还支持更多的数据类型而不仅仅是简单key-value结构的数据记录.Redis还支持对这些数据类型做更多的服务端操作 ...

  10. SQL Server-聚焦INNER JOIN AND IN性能分析(十四)

    前言 本节我们来讲讲联接综合知识,我们在大多教程或理论书上都在讲用哪好,哪个性能不如哪个的性能,但是真正讲到问题的实质却不是太多,所以才有了本系列每一篇的篇幅不是太多,但是肯定是我用心去查找许多资料而 ...