项目开发中的匿名内部方法总结

简介: 项目开发中的匿名内部方法总结

问题引入

先来看段代码:

import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
public class Test  {
    public static void main(String[] args) {
        Map<String,Object> map  = new HashMap<String, Object>(){{
            put("key1","val1");
            put("key2","val2");
        }};
        String str = new Gson().toJson(map);
        System.out.println("str: "+str);
    }
}

输出:

str: null

初始化HashMap时,这里的双括号到底什么意思代表什么呢?先来看段代码

public class Test {
 public Test() {
  System.out.println("Constructor called:构造器被调用");
 }
 static {
  System.out.println("Static block called:静态块被调用");
 }
 {
  System.out.println("Instance initializer called:实例初始化块被调用");
 }
 public static void main(String[] args) {
  new Test();
  System.out.println("=======================");
  new Test();
 }
}

输出:

 Static block called:静态块被调用
 Instance initializer called:实例初始化被调用
 Constructor called:构造器被调用
 =======================
 Instance initializer called:实例初始化被调用
 Constructor called:构造器被调用

问题分析

也就是说第一层括弧实际是定义了一个匿名内部类 (Anonymous Inner Class),第二层括弧实际上是一个实例初始化块 (instance initializer block),这个块在内部匿名类构造时被执行。这个块之所以被叫做“实例初始化块”是因为它们被定义在了一个类的实例范围内。

上面代码如果是写在 Test 类中,编译后你会看到会生成 Test$1.class 文件,反编译该文件内容:

import java.util.HashMap;
class Test$1 extends HashMap // 创建了一个 HashMap 的子类
 {
 Test$1()
 {    // 第二个 {} 中的代码放到了构造方法中去了 
     put("key1","val1");
     put("key2","val2");
 }
 }

问题总结(匿名内部类写法的潜在问题)

  文章开头提到的写法的好处很明显就是一目了然。这里来罗列下此种方法的坏处,如果这个对象要串行化,可能会导致串行化失败。

 1.此种方式是匿名内部类的声明方式,所以引用中持有着外部类的引用。所以当串行化这个集合时外部类也会被不知不觉的串行化,当外部类没有实现serialize接口时,就会报错。

2.上例中,其实是声明了一个继承自HashMap的子类。然而有些串行化方法,例如要通过Gson串行化为json,或者要串行化为xml时,类库中提供的方式,是无法串行化HashSet或者HashMap的子类的,从而导致串行化失败。解决办法:重新初始化为一个HashMap对象

new HashMap(map)

这种写法,推而广之,在初始化 ArrayList、Set 的时候都可以这么玩,比如你还可以这么玩:

 List<String> names = new ArrayList<String>() {
 {
 for (int i = 0; i < 10; i++) {
  add("A" + i);
 }
 }
 };
 System.out.println(names.toString()); // [A0, A1, A2, A3, A4, A5, A6, A7, A8, A9]


目录
相关文章
|
7月前
|
C# 开发者
C# 10.0中的文件范围命名空间:简化代码组织的新方式
【1月更文挑战第18天】C# 10.0引入了文件范围的命名空间,这是一种新的语法糖,用于更简洁地组织和管理代码。文件范围命名空间允许开发者在每个文件的基础上定义命名空间,而无需显式使用花括号包裹整个文件内容。本文将深入探讨文件范围命名空间的工作原理、使用场景以及它们为C#开发者带来的便利。
|
4月前
|
Shell Python 容器
Python模块是其代码组织和重用的基本方式。
【8月更文挑战第18天】Python模块是其代码组织和重用的基本方式。
40 1
|
4月前
|
前端开发 开发者 数据格式
|
4月前
|
存储 运维 前端开发
中后台前端开发问题之定义编排对象如何解决
中后台前端开发问题之定义编排对象如何解决
28 0
|
6月前
|
C++
友元是一种允许某些外部函数或类访问另一个类的成员的机制
友元是C++中的一个强大特性,它提供了一种机制来允许特定的外部函数或类访问私有和保护成员。正确使用友元可以增强程序的功能性和灵活性,但应谨慎使用以避免破坏封装性和增加代码的复杂度。在设计类和功能时,合理利用友元,可以使得C++程序更加有效和高效。
53 2
|
设计模式 Java 数据库连接
JAVA设计模式8:装饰模式,动态地将责任附加到对象上,扩展对象的功能
JAVA设计模式8:装饰模式,动态地将责任附加到对象上,扩展对象的功能
|
存储 安全 Java
基础一:一切都是对象
基础一:一切都是对象
104 0
|
安全 C++ Windows
C++调用外部应用程序的方法的整理总结(常用)
一、三个SDK函数:  WinExec,ShellExecute ,CreateProcess可以实现调用其他程序的要求,其中以WinExec最为简单,ShellExecute比WinExec灵活一些,CreateProcess最为复杂。
3038 0
|
设计模式 前端开发 C#
C#开发中使用委托的作用和好处
先看概念,什么是委托? 从程序的角度来讲:你就可以把委托看成是用来执行方法(函数)的一个“指针” 通俗的说就是:通过委托,我们可以把方法当成参数传递。 这里我举个例子:“设想,如果我们写了一个厨师做菜的方法,里面有拿菜、切菜、配菜、炒菜四个步骤,但编写此方法代码的人想让配菜这个环节让调用方法的人来实现,换句话说,就是想把方法作为参数来传递,那么怎么来实现呢? 方法1:使用接口,这里不是我们讨论的。
7567 0
|
存储 Go
第三十章 使用系统监视器 - 编写用户定义的应用程序监视器类
第三十章 使用系统监视器 - 编写用户定义的应用程序监视器类
114 0
下一篇
DataWorks