title: Java创建List、Map等集合对象的同时进行赋值操作

date: 2019-11-28 23:25:47

tags: JavaSE

categories: JavaSE


问题简介

  在Java当中,若希望在创建数组的同时给数组赋值很简单,可以想下面这样:

int[] num = {1,2,3};
String strs = {"a", "b", "c"}

  但是,如果我们创建List集合,或者Map集合时,也想快速地为它赋初始值,应当如何做呢?

解决方式

方式1:调用函数

  请看如下代码:

ArrayList<String> list = new ArrayList<>(Arrays.asList("aa", "bb", "cc"));

  Arrays.asList(T... a) 方法的参数是一个可变长参数,也就是说他能够传入一个数组,也能够传入多个参数,而它的作用就是将传入的数组或多个数据封装成List集合返回,而上面的代码就是接收返回的List集合,并将其作为参数传入ArrayList的构造方法,创建一个新的ArrayList对象。

  说到这里有人可能要问了,为什么不能直接将asList方法的返回值赋给list参数,而要将它传入构造器创建新的对象呢?这不是脱裤子放屁——多此一举吗。当然不是,请看下面的代码:

// 代码1
List<String> list1 = Arrays.asList("aa", "bb", "cc");
list1.add("dd"); // UnsupportedOperationException // 代码2
String[] str = {"a","b","c"};
List<String> list = Arrays.asList(str);
str[0] = "e"; // list中的0号位置也一同改变

  上面有两段代码,看似没有问题,但是运行结果却和大家想象的有些不同。首先代码1,使用asList方法返回的创建的List对象,不允许进行修改操作,否则将会抛出一个UnsupportedOperationException;再来看代码2,我们将一个数组作为asList的参数,得到一个List对象,但是此时我们改变这个数组中元素的值,list对象的值也会发生改变,因为这个List对象底层引用的就是这个数组,并且和代码1一样,这个list也不能修改。

  但是,若我们将返回的List对象作为参数传入ArrayList的构造器中,这个问题就不会发生,因为ArrayList的构造器将会把传入的list中所有的元素复制一份,因此不会影响到原数组,且可以随意改变。

方式2:匿名内部类

  这是一个非常机智的方式,就是看到了下面这行代码,我才忍不住写了这篇博客:

List<String> list = new ArrayList<String>(){ {add("a"); add("b"); add("c");} };

  乍一看是不是有点懵逼,我们将这段代码展开来看,就会清晰很多:

List<String> list = new ArrayList<String>() {
{
add("a");
add("b");
add("c");
}
};

  这下应该比之前容易理解了。这段代码就是创建了一个匿名内部类对象,且这个类继承自ArrayList,在这个匿名内部类中添加了一个非静态代码块,并在代码块中调用了三次add方法,为这个List对象赋值。

  我们知道,若我们想创建一个对象,可以直接new 构造方法,但是我们若想写一个匿名内部类,这个匿名内部类继承自某个类,只需在构造方法后面加上一对大括号。同时,非静态代码块会在构造方法执行前被执行,所以我们将赋值语句放在了代码块中,于是就有了上面这段代码。若还是看不明白,没关系,看下面这段代码十有八九就明白了,我们将上面的代码换另一种方式写出来:

public class Test {
public static void main(String[] args) {
List<String> list = new MyList();
} }
// 创建一个类继承自ArrayList
class MyList extends ArrayList{
// 在类的非静态代码块中编写赋值语句
{
add("a");
add("b");
add("c");
}
}

  以上代码就是最开始那句代码的完整版,创建一个MyList类(名字随意),继承自ArrayList,并编写一个非静态代码块调用三次add方法,这个代码块将会在构造方法执行前被执行,因此创建一个MyList对象后,它肯定已经有三条数据了。若到此时还没有听懂,可能就需要去了解一下匿名内部类,以及代码块的执行机制了。

  这种为集合赋值的好处就是,它可以用在任意一种集合类型上(Map,Set......),如下代码:

// 使用此方法为map赋值
HashMap<String, Integer> map = new HashMap<String, Integer>() {
{
put("a", 1);
put("b", 2);
put("c", 3);
}
};

  当然,这种方法也有一些弊端,就拿ArrayList来说,那就是这种方法得到的对象,它的类型并不是ArrayList,我们调用对象.getClass().getName()方法获取对象的类名,得到的是代码所在类的类名+$1(这里和匿名内部类的机制有关,就不详细叙述了)。所以在代码中,如果对对象的类型有着严格的要求,就需要谨慎考虑是否应该使用这种方式。

博客总结

  在平常编写代码时,还是第一种方式使用的比较多,因为简单而且不容易产生问题;而第二种方,我个人建议还是少用(虽然我就是为第二种方式写的博客.....),因为在类型要求严格的程序中,可能会产生问题。当然,第二种方式真的非常机智(感叹),而且可以用在各种类型的集合上,学习一下还是很有帮助的。

参考文献

《Java核心技术 卷Ⅰ》

Java创建List、Map等集合对象的同时进行赋值操作的更多相关文章

  1. java IO之 序列流 集合对象Properties 打印流 流对象

    序列流 也称为合并流. SequenceInputStream 序列流,对多个流进行合并. SequenceInputStream 表示其他输入流的逻辑串联.它从输入流的有序集合开始,并从 第一个输入 ...

  2. java创建TXT文件并进行读、写、修改操作

    import java.io.*; /**  *   * 功能描述:创建TXT文件并进行读.写.修改操作  *        * @author <a href="mailto:zha ...

  3. java基础复习之对于String对象,能够使用“=”赋值,也能够使用newkeyword赋值,两种方式有什么差别?

    String类型是实际工作中经经常使用到的类型,从数据类型上划分,String是一个引用类型,是API中定义的一个类.所以String类型的对象能够用new创建,比如String name=new S ...

  4. Java入门教程十二(集合与泛型)

    在 Java 中数组的长度是不可修改的.然而在实际应用的很多情况下,无法确定数据数量.这些数据不适合使用数组来保存,这时候就需要使用集合. Java 的集合就像一个容器,用来存储 Java 类的对象. ...

  5. Java基础知识强化之集合框架笔记53:Map集合之Map集合的遍历 键值对对象找键和值

    1. Map集合的遍历(键值对对象找键和值) Map -- 夫妻对  思路:  A: 获取所有结婚证的集合  B: 遍历结婚证的集合,得到每一个结婚证  C: 根据结婚证获取丈夫和妻子 转换:  A: ...

  6. java 创建匿名对象及声明map list时初始化

    java 创建匿名对象 类似于c# 中的 new { a:"aaa",b:"bbb"}; 1 创建匿名对象Object myobj = new Object() ...

  7. JSon_零基础_003_将Map集合对象转换为JSon格式的对象字符串,返回给界面

    将Map集合对象转换为JSon格式的对象字符串,返回给界面 需导入的jar包: 编写servlet: package com.west.webcourse.servlet; import java.i ...

  8. Java之数组array和集合list、set、map

    之前一直分不清楚java中的array,list.同时对set,map,list的用法彻底迷糊,直到看到了这篇文章,讲解的很清楚. 世间上本来没有集合,(只有数组参考C语言)但有人想要,所以有了集合 ...

  9. Java基础知识强化之集合框架笔记59:Map集合之TreeMap(TreeMap<String,String>)的案例

    1. TreeMap类的概述: 键是红黑树结构,可以保证键的排序和唯一性. 2. TreeMap案例: TreeMap<String, String> 代码示例: package cn.i ...

随机推荐

  1. \t \r \n转义字符

    t \r \n都是转义字符,空格就是单纯的空格,输入时可以输入空格 \t 的意思是 横向跳到下一制表符位置 \r 的意思是 回车 \n 的意思是回车换行 所有的转义字符和所对应的意义: 转义字符 意义 ...

  2. MySQL数据库(六) —— SQL注入攻击、视图、事物、存储过程、流程控制

    SQL注入攻击.视图.事物.存储过程.流程控制 一.SQL注入攻击 1.什么是SQL注入攻击 import pymysql conn = pymysql.Connect( user="roo ...

  3. Java目录事件

    当文件系统中的对象被修改时,我们可以监听watch服务以获取警报.java.nio.file包中的以下类和接口提供watch服务. Watchable接口 WatchService接口 WatchKe ...

  4. ubuntu 无pthread

    由于学习多线程编程,所以用到pthread,但是man的时候却发现没有pthread函数库的手册页,然后安装 $sudo apt-get install glibc-doc 安装以后,发现还是有很多函 ...

  5. LBP算子

    LBP算子特点 LBP(Local Binary Pattern),即局部二值模式,属于一种图像预处理算法,具有光照不变性和旋转不变性. 我目前做的项目是人脸表情识别,采用这种算法可以减少光照和人脸旋 ...

  6. 3-vim-打开和新建文件-02-删除交换文件

    vim的异常处理 如果vim异常退出,在磁盘上可能会保存有交换文件. 若使用vi编辑该文件时看到如下图信息,按下字母d就可以删除交换文件. 注意:输入命令操作的时候关闭输入法.

  7. android应用的资源

    应用资源可以分为两大类: 1.无法直接访问的原生资源,保存在asset目录下. 2.可以通过R资源清单类访问的资源,保存在res目录下. 资源的类型以及存储方式: android要求在res目录下用不 ...

  8. 深度探索C++对象模型之第三章:数据语义学

    如下三个类: class X { }: class Y :public virtual X { }; class Z : public virtual X {}; class A :public Y, ...

  9. node 模板引擎使用的步奏

    //定义模板引擎 app.engine('html',swig.renderFile);//设置模板引擎所存放的位置app.set('views','/views');//注册所使用的模板引擎app. ...

  10. cocos2D-X 常见49种Action

    bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !CCLayer::init( ...