在实际的项目中看到一个很奇怪的现象,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. 前端构建大法 Gulp 系列 (三):gulp的4个API 让你成为gulp专家

    系列目录 前端构建大法 Gulp 系列 (一):为什么需要前端构建 前端构建大法 Gulp 系列 (二):为什么选择gulp 前端构建大法 Gulp 系列 (三):gulp的4个API 让你成为gul ...

  2. 测试计划(Test Plan)

    测试计划(Test Plan) 版权声明:本文为博主原创文章,未经博主允许不得转载. 测试计划的概念: 测试计划是一个文档,描述了进行测试的测试范围,测试策略和方法,测试资源和进度.是对整个测试活动进 ...

  3. Linux 服务器 安装 memcached

    linux centos 一.memcached的安装 1.下载 memcached-1.4.33.tar.gz.libevent-2.0.22-stable.tar.gz 安装 memcached ...

  4. Android之常见问题集锦Ⅰ

     Android中如何在ViewPager中使动态创建的ImageView铺满屏幕 最近在做东西的时候,有一个要求,就是把用于在ViewPager里面轮播的图片铺满屏幕,但是中间遇到的问题是,Imag ...

  5. 快速开发框架CRL3.0发布,附带最新的项目示例CRLShoppingDemo

    继上次使用CRL实现大数据分库分表方案升级到2.4,时隔不久又升级到了大版本号3.0,主要是因为结构发生了一些更改 ORM和业务封装Package分开了,增加了实例项目演示代码CRLShoppingD ...

  6. ORA-01034:ORACLE not available问题的解决方法

    同时在自己电脑上装了oracle客户端和服务器,上次还能用呢,这次突然用不了. [oracle@R39i oracle]$ sqlplus scott/tiger SQL*Plus: Release ...

  7. 线上bug的解决方案--带来的全新架构设计

    缘由 本人从事游戏开发很多年一直都是游戏服务器端开发. 因为个人原因吧,一直在小型公司,或者叫创业型团队工作吧.这样的环境下不得不逼迫我需要什么都会,什么做. 但是自我感觉好像什么都不精通..... ...

  8. 在DevExpress程序中使用SplashScreenManager控件实现启动闪屏和等待信息窗口

    在我很早的WInform随笔<WinForm界面开发之"SplashScreen控件">有介绍如何使用闪屏的处理操作,不过那种是普通WInform和DevExpress ...

  9. redis安装记录

    下载redishttps://redis.io/    下载 3.2.6版本 ,上传到服务器 . 解压tar -zxvf redis-3.2.6 .tar.gz 修改配置文件(修改redis.conf ...

  10. HashMap与HashTable的区别

    HashMap和HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的问题不涉及到HashSet和H ...