JAVA_匿名内部类

map是我们常用的对象,对应map的初始化,正常来说,是需要以下这写法的。

// 正常map初始化
Map<String,Integer> mapTest01 = new HashMap<String,Integer>();
mapTest01.put("张三",100);
mapTest01.put("李四",50);
mapTest01.put("王五",70);
System.out.println(mapTest01.toString());
// 结果:{李四=50, 张三=100, 王五=70}

但是,创建map并立即初始化的话,可以使用以下方法:

Map<String,Integer> mapTest02 = new HashMap<String,Integer>(){{
    put("张三",100);
    put("李四",50);
    put("王五",70);
}};
System.out.println(mapTest02.toString());
// 结果:{李四=50, 张三=100, 王五=70}

在new后边加了{},这种写法,在写简单线程的时候应该也有用到吧?

// 简单的线程
new Thread(){
    @Override
    public void run(){
        for (int i =0; i < 3; i++){
            System.out.println("Thread执行" + i);
        }
    }
}.start();
System.out.println("Thread开始");
// 结果:
// Thread开始
// Thread执行0
// Thread执行1
// Thread执行2

这,就是匿名内部类的写法。写法格式如下:

new 父类构造器(参数列表)|实现接口()    
{    
 //匿名内部类的类体部分    
}  

简单的说,使用目的是创建,或者说new出一个对象;new之后跟着的,是要继承的父类或者实现的接口;内部类创建实例后马上被使用,或保存,或者像上边的简单线程一样,自己执行。

OK,匿名内部类是知道了,总之就是new xxx()之后,加个{}嘛~
那么,map初始化的HashMap<String,Integer>(){{......}};中的{{}}是什么?构造?不,是在对象创建时,用于给成员变量进行初始化的构造代码块

匿名内部类由于是在使用时才创建的,所以所有静态static相关的东西都
都无法使用:

Map<String,Integer> mapTest03 = new HashMap<String,Integer>(){
    static String name = "王五"; //  static语句出现编译异常:Inner classes cannot have static declarations
    {
        put("张三",100);
    }
};

另外,我们使用map初始化的话,比如统计个值,然后分组放到map里什么的,就可能想先定义一个变量,然后保存进去,如下:

String strName = "张三";
Integer score = 100;
Map<String,Integer> mapTest04 = new HashMap<String,Integer>(){{
    put(strName,score);
}};

这时候还是很正常的,但是以下语句却不行了。

// 匿名内部类,的参数使用
String strName = "张三";
Integer score = 100;
score = 40;
Map<String,Integer> mapTest05 = new HashMap<String,Integer>(){{
    strName = "李四";    // strName语句出现编译异常:Variable 'strName' is accessed from within inner class, needs to be final or effectively final
    put(strName,score); // score语句出现编译异常:Variable 'score' is accessed from within inner class, needs to be final or effectively final
}};

匿名内部类的变量需要final?这是为什么呢?
从编译器的角度来说,java的匿名内类实际上还是创建了对应的[.class]文件,有对应的类,而匿名内部类中的外部变量,不是直接使用的外部变量,而是先构造传入,然后使用的。这其中又涉及到参数问题,所以java为了防止混淆,规定了匿名内部类要用final,阻止在匿名内部类内部,改变外部变量的值。
我的测试类java文件名为【testOf_JAVA_anonymousInternal.java】,编译后,除了本身的.class文件以外,匿名内部来也依次,生成了附加$X的class文件,比如上边mapTest04的例子,匿名内部类是第三个,于是【testOf_JAVA_anonymousInternal$3.class】的内容如下:

final class testOf_JAVA_anonymousInternal$3
  extends HashMap<String, Integer>
{
  testOf_JAVA_anonymousInternal$3(String paramString, Integer paramInteger){
    put(this.val$strName, this.val$score);
  }
}
posted @ 2018-04-16 10:55  常烦常乐  阅读(188)  评论(0编辑  收藏  举报