目录
一 集合框架的概述
2.1 数组在存储多个数据方面的特点
2.2 数组在存储多个数据方面的缺点
2.3 集合存储的特点
二、集合框架
1、Collection接口:单列接口,用来存储一个一个的对象
1)List接口:存储有序的、可重复的数据 (类似于 动态数组)
①ArrayList :作为List接口的主要实现类,线程不安全,效率高;底层使用Object[ ] elementData存储,允许null值
②LinkedList : 底层使用双向链表存储;对于频繁的插入、删除操作,使用此类效率比ArryList高,允许null值,线程不安全
③Vector : 作为LIst接口的古老实现类,线程安全,效率低;底层使用Object[]elementData存储
2)set接口:存储无序的、不可重复的数据 (类似高中讲的集合)
①HashSet :作为Set接口的主要实现类,线程不安全:可以存储一个null值,底层:基于HashMap实现,而HashMap底层基于哈希表实现,哈希表(数组+链表的结构)
②LinkedHashSet : 作为HashSet的子类,遍历其内部子类是,可以按照添加的顺序遍历,只能允许一个null值
③TreeSet : 可以按照添加对象的指定属性进行排序,不允许null值
2、Map接口:双列集合,用来存储一对(key-value)一对的数据 (类似于高中讲的函数)
1)HashMap : 作为Map的主要实现类;线程不安全,效率高;存储null的key和value
2)TreeMap:保证按照添加的key—-value对进行排序,实现排序遍历(底层使用红黑树)
3) Hashtable :作为古老的实现类;线程安全的;效率低;不能存储null的key和value
List和String数组之间的直接转换
1、集合 、数组都是对多个数据进行存储操作的结构,简称java容器
说明:此时的存储,主要是指内存层面的存储,不涉及到持久化的存储
> 一旦被初始化以后,其长度也就确定了
> 数组一旦定义好,其元素类型也就确定了,我们也就只能操作指定类型的数据了
比如;String[] arr;int [] arr1;
>一旦初始化以后,其长度不能修改
>数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不变,同时效率不高
>获取数组中实际元素的个数的需求,数组没有现成的属性和方法可用
>数组存储数据的特点:有序、可重复,对于无序、不可重复的需求不能满足
>数组的功能性较弱(没有方法,只有一个属性,只能存值取值,遍历)
>基本类型数组可以存储基本类型, 引用类型数组可以存储引用类型
1 长度不固定,可以存储多个数据
2 允许存储多种数据 , (但是,经验上大部分还是存值同一类型)
3 有些集合允许重复元素,有些集合不允许重复
4 有些集合有顺序,有些集合无序
5 集合提供了丰富的API来操作集合,及集合中的元素
6 集合只能存储引用数据类型
List常用方法
void add(int index, object ele):在index位置插入ele元素
boolean addAll(int index,collection eles ) :从index位置开始将eles.中的所有元素添加进来Object get(int index):获取指定index位置的元素
int indexof(object obj):返回obj在集合中首次出现的位置
int lastIndexof(object obj):返回obj在当南集合中末次出现的位置object remove(int index)∶移除指定index位置的元素,并返回此元素
object set(int index,Object ele):设置指定index位置的元素为eLe
List sublist(int fromIndex, int toIndex):返回从fromIndex至toIndex位置的子集合
a、ArrayList源码分析(jdk 7 情况下)
ArrayList list = new ArrayList(); // 底层创建了长度是10的Object[]数组elementData
list.add(123); //elementData[0]=new Integer(123);
....
list.add(11);//如果此次的添加导致底层elementData数组容量不足,则扩容,
默认情况下,扩容为原来容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中
结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity);
b、ArrayList源码分析(jdk 8 情况下)
ArrayList list = new ArrayList();//底层Object[]数组elementData初始化为{},并没有创建长度为10的数组
list.add(123);//第一次调用add()时,底层才创建了长度为10的数组,并将123添加到elementData数组中
后续添加和扩容与jdk 7 无异
LinkedList源码分析:
LinkedList list m new linkedList(); 内部声明了Node类型的first和Last属性,默认值为 null
list.add(123);//将123封装到Node中,创建了Node对象。
其中,Node定义为:
private static class Node(
E item;
Nodenext; Node
prev;
Node(Nodeprev, E eLement,Node next){ ithis.item = eLement;
this.next = next;this.prev = prev;
}
}
①、②和③的异同?
同:三各类都实现了List接口,存储数据的特点相同、可重复的数据
不同:见上
Set接口是Collection的子接口,set接口没有提供额外的方法
Set集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set集合中,则添加操作失败。
Set判断两个对象是否相同不是使用==运算符,而是根据equals()方法
不可重复性;保证添加的元素按照equal()判断时,不能返回true。即相同元素只能添加一个
Set没有下标操作的方法
添加元素的过程:以Hashset为例:
我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,
此哈希值按者通过某种算法计算出HashSet底层数组中的存放位置(即为:索引位置),判断
数组此位置上是否已经有元素:
如果此位置上没有其他元素,则元素添加成功。
如果此位置上有其他元素b(成以健表形式存在的事个元素),则比较元素a与元素b的hash值:
如果hash值不相同,则元素a添加成功。
如果hash值相同,进而需要调用元素a所在类的equlas()方法:
equals()返回true,元素a添加失败
equals()返回false,则元素a添加成功。
HashSet是 Set接口的典型实现,大多数时候使用Set集合时都使用这个实现类。
HashSet按 Hash 算法来存储集合中的元素,因此具有很好的存取、查找、删除性能。
HashSet具有以下特点:
≥不能保证元素的排列顺序>HashSet不是线程安全的
≥集合元素可以是null
HashSet集合判断两个元素相等的标准:两个对象的equals方法相等,并且hashCode方法返回值也相等。
对于存放在Set容器中的对象,对应的类一定要重写equals()和hashCode(Objectobj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的放列码”。
LinkedHashSet 是 HashSet的子类
LinkedHashSet 根据元素的hashCode值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
LinkedHashSet 插入性能略低于 HashSet,但在迭代访问Set里的全部元素时有很好的性能。
LinkedHashSet 不允许集合元素重复。
对于频繁的遍历操作LinkedHashSet的效率要高于HashSet
TreeSet是 SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。TreeSet底层使用红黑树结构存储数据
新增的方法如下:(了解)
>Comparator comparator()>Object first()
>Object last()
>Object lower(Object e)>Object higher(Object e)
>SortedSet subSet(fromElement, toElement)>SortedSet headSet(toElement)
>SortedSet tailSetfromElement)
TreeSet两种排序方法:自然排序和定制排序。默认情况下,TreeSet采用自然排序。
两种排序方法来定制集合内元素相同的标准
a) TreeSet的自然排序
在自然排序中比较两个对象是否相同的标准为:compareTo()返回0,不再是equals()
要想自定义自然排序有如下:
实现Comparable接口,重写compareTO()方法
题目需求如下:
/**
* @Description TODO
* @Created by Administrator
* @Date 2021/7/26 20:06
*/
public class Worker implements Comparable{
private int age;
private String name;
private double salary;
public Worker() {
}
public Worker(int age, String name, double salary) {
this.age = age;
this.name = name;
this.salary = salary;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public void work() {
System.out.println(name + "work");
}
@Override
public String toString() {
return "Worker{" +
"age=" + age +
", name='" + name + '\'' +
", salary=" + salary +
'}';
}
// @Override
// public boolean equals(Object o) {
// if (this == o) return true;
// if (o == null || getClass() != o.getClass()) return false;
// Worker worker = (Worker) o;
// return age == worker.age &&
// Double.compare(worker.salary, salary) == 0 &&
// Objects.equals(name, worker.name);
// }
//重写compareTo方法
@Override
public int compareTo(Object o) {
if(o instanceof Worker){
Worker worker=(Worker)o;
//先比较年龄,
int compare = Integer.compare(this.age, worker.age);
//如果年龄相等,再比较工资
if(compare==0){
int compare1 = Integer.compare((int) this.salary, (int) worker.salary);
//如果工资相等,再比较姓名
if(compare1==0){
return this.name.compareTo(worker.name);
}
else { //工资不相等,返回工资比较结果
return compare1;
}
}else { //年龄不相等,返回年龄排序结果
return compare;
}
}else {
return 0;
}
}
}
/**
* @Description TODO
* @Created by Administrator
* @Date 2021/7/26 19:33
*/
public class TestSet {
public static void main(String args[]) {
TreeSet set = new TreeSet<>();
set.add(new Worker(18,"zhang3",1500));
set.add(new Worker(18,"li4",1500));
set.add(new Worker(18,"wang5",1600));
set.add(new Worker(17,"zhao6",2000));
Iterator iterator = set.iterator();
while (iterator.hasNext()){
Worker next = iterator.next();
System.out.println(next);
}
}
}
b) TreeSet的定制排序
在定制排序中,比较两个对象是否相同的标准为:compare()返回0,不再是equals()
要想实现定制排序需要如下两个步骤:
1、实现Comparator接口,重写compare方法
2、使用TreeSet的有参构造方法,传入Comparator对象
下面给个示例,利用定制排序按照员工的工资从很小到大排序
public class TestSet {
public static void main(String args[]) {
Comparator com = new Comparator() {
//按照工资从小到大排序
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Worker && o2 instanceof Worker){
Worker w1 = (Worker)o1;
Worker w2 = (Worker)o2;
return Integer.compare((int)w1.getSalary(),(int)w2.getSalary());
}else {
return 0;
}
}
};
TreeSet set = new TreeSet<>(com);
set.add(new Worker(18,"zhang3",1500));
set.add(new Worker(18,"li4",1400));
set.add(new Worker(18,"wang5",1600));
set.add(new Worker(17,"zhao6",2000));
Iterator iterator = set.iterator();
while (iterator.hasNext()){
Worker next = iterator.next();
System.out.println(next);
}
}
}
Map与Collection并列存在。用于保存具有映射关系的数据:key-value
Map 中的 key 和 value 都可以是任何引用类型的数据
Map 中的 key 用Set来存放,不允许重复,即同一个 Map 对象所对应 的类,须重写hashCode()和equals()方法
常用String类作为Map的“键”
key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到 唯一的、确定的 value
Map接口的常用实现类:HashMap、TreeMap、LinkedHashMap和 Properties。其中,HashMap是 Map 接口使用频率最高的实现类
常用方法
添加、删除、修改操作:
Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
void putAll(Map m):将m中的所有key-value对存放到当前map中
Object remove(Object key):移除指定key的key-value对,并返回value
void clear():清空当前map中的所有数据
元素查询的操作:
Object get(Object key):获取指定key对应的value
boolean containsKey(Object key):是否包含指定的key
boolean containsValue(Object value):是否包含指定的value
int size():返回map中key-value对的个数
boolean isEmpty():判断当前map是否为空
boolean equals(Object obj):判断当前map和参数对象obj是否相等
元视图操作的方法:
Set keySet():返回所有key构成的Set集合
Collection values():返回所有value构成的Collection集合
Set entrySet():返回所有key-value对构成的Set集合
底层存储:数组+链表 (jdk 7及之前) 数组+链表+红黑树(jdk 8)
只能有一个null的key,可以有多个null的value
HashMap集合判断两个元素相等的标准:两个对象的equals方法相等,并且hashCode方法返回值也相等。
底层实现原理
jdk 7 时 (扩容时默认扩容为原来的2倍)
HashMap map = new HashMap():
在实例化以后,底层创建7长度是16的一-维数组Entry[] table.
...可能已经执行过多次put...
map. put(key1, value1):
首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry 数组中的存放位置。
如果此位置上的数据为空,此时的key1-value1 添加成功。
如果此位置上的数据不为空,(意味者此位业上存在一个成多个数据(以链表形式存在))。比较key1和已经存在的一个或多个数据的哈希值:
如果key1的哈用值与已经存在的数据的哈用值都不相同,此时key1-value1 调加成功。
如果key1的哈希值和已经存在的某一个数据(key2-value2) 的哈希值相同,继续比较:调用key1所在类的equals(key2)
如果equals()返回false;此时key1 value1添加成功。
如果equals()返回true:使用value1替换value2。
jdk 8 时
jdk8相较于jdk7在底层实现方面的不同:
1. new HashMap():底层没有创建一个长度为16的数组
2. jdk 8底层的数组是: Node[], 而非Entry[]
3.首次调用put()方法时, 底层创建长度为16的数组
4. jdk7底层结构只有:数组+链表。jdk8 中底层结构:数组+链表+红黑树。
当数组的某一个索引位置上的元素以链表形式存在的数据个数> 8且当前数组的长度> 64时,
此时此索引位置上的所有数据改为使用红黑树存储。
源码分析
1. HashMap 的数据结构
在 java 编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引 用),所有的数据结构都可以用这两个基本结构来构造的,HashMap 也不例外。HashMap 实际上是一个“链表散列”的数据结构,即数组和链表的结合体。
从上图中可以看出,HashMap 底层就是一个数组结构,数组中的每一项又是一个链表。 当新建一个 HashMap 的时候,就会初始化一个数组。
2. HashMap 的存取实现:
1)存储
public V put(K key, V value) {
2. // HashMap 允许存放 null 键和 null 值。
3. // 当 key 为 null 时,调用 putForNullKey 方法,将 value 放置在数组第一个位置。
4. if (key == null)
5. return putForNullKey(value);
6. // 根据 key 的 keyCode 重新计算 hash 值。
7. int hash = hash(key.hashCode());
8. // 搜索指定 hash 值在对应 table 中的索引。
9. int i = indexFor(hash, table.length);
10. // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素。
11. for (Entry e = table[i]; e != null; e = e.next) {
12. Object k;
13. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
14. V oldValue = e.value;
15. e.value = value;
16. e.recordAccess(this);
17. return oldValue;
18. }
19. }
20. // 如果 i 索引处的 Entry 为 null,表明此处还没有 Entry。
21. modCount++;
22. // 将 key、value 添加到 i 索引处。
23. addEntry(hash, key, value, i);
24. return null;
25. }
从上面的源代码中可以看出:当我们往 HashMap 中 put 元素的时候,先根据 key 的 hashCode 重新计算 hash 值,根据 hash 值得到这个元素在数组中的位置(即下标),如 果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新 加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到 此数组中的该位置上。 addEntry(hash, key, value, i)方法根据计算出的 hash 值,将 key-value 对放在数组 table 的 i 索引处。addEntry 是 HashMap 提供的一个包访问权限的方法,代码如下:
void addEntry(int hash, K key, V value, int bucketIndex) {
2. // 获取指定 bucketIndex 索引处的 Entry
3. Entry e = table[bucketIndex];
4. // 将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entr
y
5. table[bucketIndex] = new Entry(hash, key, value, e);
6. // 如果 Map 中的 key-value 对的数量超过了极限
7. if (size++ >= threshold)
8. // 把 table 对象的长度扩充到原来的 2 倍。
9. resize(2 * table.length);
10. }
当系统决定存储 HashMap 中的 key-value 对时,完全没有考虑 Entry 中的 value,仅仅 只是根据 key来计算并决定每个 Entry的存储位置。我们完全可以把 Map 集合中的 value 当 成 key 的附属,当系统决定了 key 的存储位置之后,value 随之保存在那里即可。
hash(int h)方法根据 key 的 hashCode 重新计算一次散列。此算法加入了高位计算,防 止低位不变,高位变化时,造成的 hash 冲突。
static int hash(int h) {
2. h ^= (h >>> 20) ^ (h >>> 12);
3. return h ^ (h >>> 7) ^ (h >>> 4);
4. }
我们可以看到在 HashMap 中要找到某个元素,需要根据 key 的 hash 值来求得对应数 组中的位置。如何计算这个位置就是 hash 算法。前面说过 HashMap 的数据结构是数组和 链表的结合,所以我们当然希望这个 HashMap 里面的 元素位置尽量的分布均匀些,尽量 使得每个位置上的元素数量只有一个,那么当我们用 hash 算法求得这个位置的时候,马上 就可以知道对应位置的元素就是我们要的,而不用再去遍历链表,这样就大大优化了查询的 效率。 对于任意给定的对象,只要它的 hashCode() 返回值相同,那么程序调用 hash(int h) 方 法所计算得到的 hash 码值总是相同的。我们首先想到的就是把 hash 值对数组长度取模运 算,这样一来,元素的分布相对来说是比较均匀的。但是,“模”运算的消耗还是比较大的,在 HashMap 中是这样做的:调用 indexFor(int h, int length) 方法来计算该对象应该保存 在 table 数组的哪个索引处。indexFor(int h, int length) 方法的代码如下:
1. static int indexFor(int h, int length) {
2. return h & (length-1);
3. }
这个方法非常巧妙,它通过 h & (table.length -1) 来得到该对象的保存位,而 HashMap 底层数组的长度总是 2 的 n 次方,这是 HashMap 在速度上的优化。在 HashMap 构造器中 有如下代码:
1. int capacity = 1;
2. while (capacity < initialCapacity)
3. capacity <<= 1;
这段代码保证初始化时 HashMap 的容量总是 2 的 n 次方,即底层数组的长度总是为 2 的 n 次方。当 length 总是 2 的 n 次方时,h& (length-1)运算等价于对 length 取模,也就是 h%length,但是&比%具有更高的效率。 这看上去很简单,其实比较有玄机的,我们举个例子来说明: 假设数组长度分别为 15 和 16,优化后的 hash 码分别为 8 和 9,那么&运算后的结果如下:
从上面的例子中可以看出:当它们和 15-1(1110)“与”的时候,产生了相同的结果, 也就是说它们会定位到数组中的同一个位置上去,这就产生了碰撞,8 和 9 会被放到数组中 的同一个位置上形成链表,那么查询的时候就需要遍历这个链 表,得到 8 或者 9,这样就 降低了查询的效率。同时,我们也可以发现,当数组长度为 15 的时候,hash 值会与 15-1 (1110)进行“与”,那么 最后一位永远是 0,而 0001,0011,0101,1001,1011,0111, 1101 这几个位置永远都不能存放元素了,空间浪费相当大,更糟的是这种情况中,数组可 以使用的位置比数组长度小了很多,这意味着进一步增加了碰撞的几率,减慢了查询的效率! 而当数组长度为 16 时,即为 2 的 n 次方时,2 n -1 得到的二进制数的每个位上的值都为 1, 这使得在低位上&时,得到的和原hash的低位相同,加之hash(int h)方法对key的hashCode 的进一步优化,加入了高位计算,就使得只有相同的 hash 值的两个值才会被放到数组中的同一个位置上形成链表。所以说,当数组长度为 2 的 n 次幂的时候,不同的 key 算得得 index 相同的几率较小,那么数据在数组上分布就比较均匀,也就是说碰撞的几率小,相对的, 查询的时候就不用遍历某个位置上的链表,这样查询效率也就较高了。
根据上面 put 方法的源代码可以看出,当程序试图将一个 key-value 对放入 HashMap 中时,程序首先根据该 key 的 hashCode() 返回值决定该 Entry 的存储位置:如果两 个 Entry 的 key 的 hashCode() 返回值相同,那它们的存储位置相同。如果这两 个 Entry 的 key 通过 equals 比较返回 true,新添加 Entry 的 value 将覆盖集合中原 有 Entry 的 value,但 key 不会覆盖。如果这两个 Entry 的 key 通过 equals 比较返 回 false,新添加的 Entry 将与集合中原有 Entry 形成 Entry 链,而且新添加的 Entry 位 于 Entry 链的头部——具体说明继续看 addEntry() 方法的说明。
2) 读取:
1. public V get(Object key) {
2. if (key == null)
3. return getForNullKey();
4. int hash = hash(key.hashCode());
5. for (Entry e = table[indexFor(hash, table.length)];
6. e != null;
7. e = e.next) {
8. Object k;
9. if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
10. return e.value;
11. }
12. return null;
13. }
有了上面存储时的 hash 算法作为基础,理解起来这段代码就很容易了。从上面的源代 码中可以看出:从 HashMap 中 get 元素时,首先计算 key 的 hashCode,找到数组中对 应位置的某一元素,然后通过 key 的 equals 方法在对应位置的链表中找到需要的元素。
归纳起来简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体 就是一个 Entry 对象。HashMap 底层采用一个 Entry[] 数组来保存所有的 key-value 对, 当需要存储一个 Entry 对象时,会根据 hash 算法来决定其在数组中的存储位置,在根据 equals 方法决定其在该数组位置上的链表中的存储位置;当需要取出一个 Entry 时,也会根据 hash 算法找到其在数组中的存储位置,再根据 equals 方法从该位置上的链表中取出 该 Entry。
3. HashMap 的性能参数:
HashMap 包含如下几个构造器:
HashMap():构建一个初始容量为 16,负载因子为 0.75 的 HashMap。 HashMap(int initialCapacity):构建一个初始容量为 initialCapacity,负载因子 为 0.75 的 HashMap。 HashMap(int initialCapacity, float loadFactor):以指定初始容量、指定的负载因子创建一 个 HashMap。
HashMap 的基础构造器 HashMap(int initialCapacity, float loadFactor)带有两个参数,它 们是初始容量 initialCapacity 和加载因子 loadFactor。
initialCapacity:HashMap 的最大容量,即为底层数组的长度。
loadFactor:负载因子 loadFactor 定义为:散列表的实际元素数目(n)/ 散列表的容量(m)。
负载因子衡量的是一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越 高,反之愈小。对于使用链表法的散列表来说,查找一个元素的平均时间是 O(1+a),因此如果负载因子越大,对空间的利用更充分,然而后果是查找效率的降低;如果负载因子太小, 那么散列表的数据将过于稀疏,对空间造成严重浪费。
①LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历。
原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素
对于频繁的遍历操作,此类执行效率高与HashMap
TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。 TreeMap 可以保证所有的 Key-Value 对处于有序状态。
TreeSet底层使用红黑树结构存储数据
TreeMap 的 Key 的排序:
自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有 的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口
TreeMap判断两个key相等的标准:两个key通过compareTo()方法或 者compare()方法返回0。
Properties 类是 Hashtable 的子类,该对象用于处理属性文件
由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型
存取数据时,建议使用setProperty(String key,String value)方法和 getProperty(String key)方法
Properties pros = new Properties();
pros.load(new FileInputStream("jdbc.properties"));
String user = pros.getProperty("user");
System.out.println(user);
List-->String数组
Object[] |
toArray() 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。 |
|
|
toArray(T[] a) 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。 |
一般采用第二个重载方法,指定需要转化的数组类型
String[] strings1 = new String[list.size()];
list.toArray(strings1);
注:list.size()是指当前集合的长度,一般采用的是ArrayList集合
String数组-->List
static
|
asList(T... a) 返回一个受指定数组支持的固定大小的列表。 |
String[] str={"adf","df","sde"};
List strings = Arrays.asList(str);
List集合:底层是一个数组,因此可以存放多个null
Set集合:因为在添加的时候会调用squal()方法,如果相同就会添加失败,因此所有Set集合只能存放一个null值。TreeSet不可以存放,因为他是排序,
Map集合:HashMap、LinkedHashMap可以存放一个key=null,多个value=null的值,因为若加入第二个key=null的值也会被覆盖,HashTable、TreeMap依然不可以存空。