List是列表(接口),是可以允许出现重复值的,
Set是集合,不允许出现重复值
ArrayList(一般类)实现list接口
arraylist与vector是差不多的,只不过arraylist是不同步的,而vector是同步的
vector ArrayList其实都是数组的封装
如果不涉及多线程 使用ArrayList效率会高一点。
List接口
List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数组。
和下面要提到的Set不同,List允许有相同的元素。
除了具有Collection接口必备的iterator()方法外,List还提供一个listIterator()方法,返回一个 ListIterator接口,和标准的Iterator接口相比,ListIterator多了一些add()之类的方法,允许添加,删除,设定元素,还能向前或向后遍历。
实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。
ArrayList类
ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。
size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。
每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。
和LinkedList一样,ArrayList也是非同步的(unsynchronized)。
1.
List是接口,List特性就是有序,会确保以一定的顺序保存元素.
ArrayList是它的实现类,是一个用数组实现的List.
2.
一般情况下,如果没有必要,推荐代码只同List,Map接口打交道.
比如:List list = new ArrayList();
这样做的原因是list就相当于是一个泛型的实现,如果想改变list的类型,只需要:
List list = new LinkedList();//LinkedList也是List的实现类,也是ArrayList的兄弟类
这样,就不需要修改其它代码,这就是接口编程的优雅之处.
不过现在已经有List泛型的定义了,你可以决定List里面装什么类型的数据。
3.
如果开发的时候觉得ArrayList,HashMap的性能不能满足你的需要,可以通过实现List,Map(或者Collection)来定制你的自定义类.
可以参考The Art Of Computer Programming的Sorting and Searching部分
其实往往这些集合已经够用了,没必要去自己手动定制。
Vector类(此类已经被放弃,不建议使用,作为了解)
Vector类中的所有方法都是线程同步的,两个线程并发访问Vector时对象是安全的。但只有一个线程访问Vector对象时,因为源程序仍调用了同步方法,需要额外的监视器检查,运行效率要低些。
ArrayList类中的所有方法都是同步的,所有在没有多线程安全问题的时候,最好用ArrayList,程序的效率会高些。
在有线程安全问题,且我们的程序又没有自己处理的时候,只能用Vector。
Vector只能容纳object freforences不能容纳基本类型
Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。
当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。
HashSet类
1.如何保证无序不重复
Java中每一个对象都对应一个int型的哈希码,在向HashSet添加元素时,JVM会通过对象的HashCode()方法获取此对象的哈希码,然后对某一个整数(hashSet的初始容量)求余,将这个元素放在Set中位于模数的位置。如果该位置已存在元素,即出现要把两个元素放在同一位置的时候,如s1和s2,会判断s1.equal(s2),如果值为真,说明s1和s2相同,抛弃等放入的元素。如果为假,继续遍历set里面其它的元素,调用equals方法,确保没有相同的元素后,将s2放置在另一空闲位置。为了实现及达到性能保障,应尽量做到:1).一定要保证相同对象的哈希码相同2).尽量保证不同的对象返回不同的哈希码,以尽可能保证求余后的模数相等,而减少equals的调用。但是应注意:我们永远无法保证不同的对象的哈希码就一定不同(因为哈希码是int型的,当我们申请的对象个数比int型的数据还要多时,出现相同的情况是必然)
2.初始容量和加载因子的概念
无参的构造方法生成的HashSet对象,其底层HashMap实例的默认初始容量是16,加载因子是0.75,当向hashSet中加入对象时,随着对象个数的增多,会导致模数相同的可能性越来越大,也就是需要调用equal()方法的可能性越来越大,这就导致了很多不必要的开销,为了解决这一问题,Sun公司提出了加载因子的概念,即当hashSet尚未填满时(只需达到默认初始容量*加载因子,即16*0.75),就可以动态扩大容量,(增大为原容量的2倍,即32),这样哈希码就不再是对16求模了,而是对32求模,通过多开辟空间有效地降低了时间复杂度。
3.性能分析
HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证集合的迭代顺序,特别是它不保证该顺序恒久不变。此类允许使用null元素。此类为基本操作提供了稳定性能,这些基本操作包括add、remove、contains和size,假定哈希函数将这些元素正确地颁在桶中。对此集合进行迭代所需的时间与HashSet实例的大小(元素的数量)和底层HashMap实例(桶的数量)的"容量"的和成比例。因此,如此迭代性能很重要,则不要将寝容量设置得太高(或将加载因子设置得太低).
4.同步分析
注意,此实现不是同步的。 如果多个线程同时访问一个集合,而其中至少一个线程修改了该集合,那么它必须保持外部同步。这通常是通过对自然封装该集合的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSet 方法来“包装”集合。最好在创建时完成这一操作,以防止对 HashSet 实例进行意外的不同步访问:Set s = Collections.synchronizedSet(new HashSet(...));
5.避免内存泄露
在下面的实例中,如下操作 s1.age=21; test.remove(s1);并没有真正删除s1,这是因为在Student的hashcode方法中利用age来获取哈希值,当s1在加入哈希表之后,再对age(或name)进行修改,将会改变对象的原哈希值,哈希表会根据变动调整对象的位置,而remove方法仍在试图删除原位置的对象(此时可能已经为空),最终的结果是根本没有删除成功。这样做很可能会导致大量的无效对象(而程序员误认为此类对象已经游离,可以被GC回收)存在于set中,从而导致内存泄露。如在本例中,s1 = new Student("Pato",16);之后,s1原来指向的对象,GC不会做回收操作。
6.HashSet为什么不能重复
<1>、HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束
<2>、HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的 String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例.
7.实例
import java.util.HashSet;
import java.util.Set;
/**
*
* @author 钱亮亮
*
*/
public class SetTest {
public static void main(String[] args){
//无参的构造方法生成的HashSet对象,其底层HashMap实例的默认初始容量是16,加载因子是0.75
Set<Student> test = new HashSet<Student>();
Student s1 = new Student("Mary",18);
Student s2 = new Student("Charles",20);
Student s3 = new Student("Herry",18);
test.add(s1);
test.add(s2);
test.add(s3);
System.out.println("Size of Initial: " + test.size());//3
System.out.println(test);//[Student: Charles , 20, Student: Mary , 18, Student: Herry , 18]
test.remove(s1);
System.out.println("Size of Removed: " + test.size());//2
System.out.println(test);//[Student: Charles , 20, Student: Herry , 18]
test.add(s1);
System.out.println("Size of Added: " + test.size());//3
System.out.println(test);//[Student: Charles , 20, Student: Mary , 18, Student: Herry , 18]
s1.age = 21;
test.remove(s1);
System.out.println("Size of Update-Remove: " + test.size());//3 *************************remove失效
System.out.println(test);//[Student: Charles , 20, Student: Mary , 21, Student: Herry , 18]
s1 = new Student("Pato",16);
test.add(s1);
System.out.println("Size of Added: " + test.size());//4
System.out.println(test);//[Student: Charles , 20, Student: Mary , 21, Student: Pato , 16, Student: Herry , 18]
}
}
class Student{
public String name;
public int age;
public Student(){}
public Student(String name, int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(obj == null) return false;
if(!(obj instanceof Student)) return false;
Student s = (Student)obj;
if(this.name.equalsIgnoreCase(s.name)&&this.age==s.age) return true;
else return false;
}
@Override
public int hashCode() {
return name.toLowerCase().hashCode()+age;
}
@Override
public String toString() {
return "Student: "+name+" , "+age;
}
}
分享到:
相关推荐
详细描述map、list、set的常用子类特性,各个场景的适用。
Java集合Collection、List、Set、Map使用详解
### Java集合Collection、List、Set、Map使用详解 #### 1. 集合框架概述 集合框架是Java编程语言中最基本且最重要的组成部分之一。它提供了处理数据集合的强大工具,这些工具不仅支持基本操作(如添加、删除和查找...
"Java集合Collection、List、Set、Map使用详解" Java集合是Java编程语言中最基本也是最重要的一部分。能够正确地使用集合类和理解集合的实现原理对于Java程序的开发具有无比的好处。本文将详细解释Java集合的实现...
本文将深入探讨Java集合框架中的四个主要接口:Collection、List、Set和Map,以及它们的实现原理。 ### 集合框架概述 集合框架是Java API中用于存储和管理对象的统一框架。它为数据结构提供了抽象接口,使得程序员...
#### 三、Java容器类Set详解 **1. Set接口简介** - `Set`也是`Collection`接口的一个子接口,其特点是不允许重复元素。 - 主要用于存储唯一性的元素集合,可以避免数据重复带来的问题。 - 常见实现类包括`HashSet`...
综上所述,`list`、`tuple`、`dict`和`set`各有其适用场景。`list`和`tuple`适用于有序的数据集合,其中`tuple`是不可变的;`dict`适用于需要快速查找的键值对数据结构;而`set`适用于需要去重且不关心元素顺序的...
java集合collection、list、set、map使用详解.doc
本教程将深入探讨三种主要的集合类型:List、Set和Map,以及几种常用的循环语句,如forEach、map、where、any和every。这些概念对于理解Dart中的数据处理至关重要。 1. **List**: List是有序的元素集合,可以包含...
Java 集合详解 Java 集合是 Java 里面最常用的,也是最重要的一部分。能够用好集合和理解好集合对于做 Java 程序的开发拥有无比的好处。下面将详细解释 Java 中的集合是如何实现的,以及他们的实现原理。 一、集合...
java各种集合的详解Set,List,Vector,arrayList,linkList,HashSet
java集合的详解,collection,list,set,map疑难解答,对于对容器似懂非懂的新手来说,这无疑是给你指点迷津的一个非常不错的选择,讲解内容丰富。
集合类可以分为三大类:Collection、List 和 Set。 Collection 是集合框架中的根接口,提供了基本的集合操作,如 add、remove、contains 等。Collection 接口没有实现类,因此需要通过其子接口来实现。 Set 是一个...
Java中的Set、List和Map是三个重要的集合框架接口,它们分别代表不同的数据结构,具有各自的特点和用途。 1. **List(列表)** List 是一个有序的集合,允许重复元素,可以按照索引访问。它主要有两个常用的实现类...
01_Python基本语法 基本语法&数据类型&运算符详解 02_Python常见数据类型Number,String,Tuple详解 03_Python常见数据类型List&dict&set 04_Python常见数据类型(三) 05_Python常见流程控制&循环结构