1、List
,主要就是存取上差异,所以这两者用哪个,需要看情况而定;
1)、ArrayList是一个有序结构;类似于药房放药的柜子,有很多的抽屉,每个抽屉都有一个编号,当药剂师要抓哪味药的时候只需要知道那味药的编号就能很快的取到药,这就相当于索引;但是在药柜中增加一味药的药柜时就比较麻烦了,这里先讨论在药柜中间增加的情况,比如说增加一味‘重楼‘,要放在008号药柜后面应该加一个抽屉009号,可是原先就存在009号那个抽屉,但是存放的并不是‘重楼’,而是其他药,编号肯定得是唯一的才行,那这样只有把009号开始的抽屉每个编号都加一,009变成010,这样依次类推,如果有几百个抽屉的话这样效率是不是会很低(ps:实际药店肯定不会这样做,我只是为了能和要讲的例子更贴切才想出这种情形);还有一点,比如有味药买的人比较多,所以囤的多了,一个抽屉放不下,分了好几个抽屉放,虽然是重复了,但是并不影响,因为药剂师始终是根据编号来取的;
ArrayList就是这样的结构,每个元素都有一个索引,所以在读取的时候会很快,并且里面元素也可以是重复的;但是在插入或者删除时效率不高,因为在某个元素插入或删除时,需要把它后面所有元素的索引都加一;
2)、LinkedList是链表结构;顾名思义,就跟链子类似,链子的特性是可以随意增加或拆卸中间一块,不会破坏结构,比如说一条链子太短了,我要加长(头部和尾部的这种特殊的就先不考虑,只考虑最普通的情况),是不是需要先从链子中间某个部位把相扣的两个环解开,然后取一条新的链子,前一个环扣住这条链子的头部,后一个环扣住链子的尾部,这样链子就加长了,效率很高;
LinkedList就是这种类似链子的结构,它的每个节点存了两个元素一个是存的数据,一个是指向它下一个节点的位置;所在插入的时候,只需要把前一个节点的所指向的下一个节点的位置改为刚插入进去的节点位置,刚插入进去的节点指向后一个节点的位置,插入操作就完成了;但是链表结构是没有索引的,所以查询某条记录的时候是通过碰撞发去遍历整个链表,这样效率很低;
结论:两个list各有优点,导致差异的根本原因就是结构;ArrayList适合查询,LinkedList适合插入和删除;
2、Set
Set的特点是去重,同样也是结构决定的,set其实就是一个空的容器,有数据就往里面扔,但是里面如果存在相同的数据,当前这个就不会被加进去;Set判断两个对象相同不是使用==运算符,而是根据equals方法,处理基本类型之外的其它对象在判断equals方法为true的时候会再判断hashcode值是否相等,相等时才会返回true;Set的两个子类,HashSet和TreeSet;
1)、HashSet是按照hash算法来排列的,在存取上的性能都是比较好的;
去重实例:
/**
* Created by zelei.fan on 2017/6/8.
*/
public class Person {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (age != null ? !age.equals(person.age) : person.age != null) return false;
if (name != null ? !name.equals(person.name) : person.name != null) return false;
return true;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (age != null ? age.hashCode() : 0);
return result;
}
}
import com.beust.jcommander.internal.Lists;
import com.pony.common.collection.Person;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Created by zelei.fan on 2017/7/27.
*/
public class test {
public void ship(List list){
Person p1 = new Person();
p1.setName("haha");
p1.setAge(10);
list.add(p1);
Person p2 = new Person();
p2.setName("cc");
p2.setAge(15);
list.add(p2);
Person p3 = new Person();
p3.setName("ee");
p3.setAge(12);
list.add(p3);
Person p4 = new Person();
p4.setName("ee");
p4.setAge(12);
list.add(p4);
}
public static void main(String[] args) {
test collection = new test();
List<Person> list = Lists.newArrayList();
collection.ship(list);
System.out.println(list);
/*实现list去重,将list转到set中,同时重写对象的equals和hashCode方法*/
Set<Person> set = new HashSet<Person>(list);
System.out.println(set);
}
}
打印结果:
[Person{name='haha', age=10}, Person{name='cc', age=15}, Person{name='ee', age=12}, Person{name='ee', age=12}]
[Person{name='ee', age=12}, Person{name='cc', age=15}, Person{name='haha', age=10}]
需要注意的是,如果是list中存的是对象的话,需要重写该对象的equals和hashCode方法;
2)、TreeSet是按红黑树算法存入的,所以TreeSet中会实现自动排序功能;但是性能很低,因为每插入或者删除一个元素时,需要重新按红黑算法来排列;如果需要排序的话还需要实现Comparator接口;
具体实例:
public static void main(String[] args) {
test collection = new test();
List<Person> list = Lists.newArrayList();
collection.ship(list);
System.out.println(list);
/*treeSet排序,实现Comparator接口*/
Set<Person> treeSet = new TreeSet<Person>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge().compareTo(o2.getAge());
}
});
treeSet.addAll(list);
System.out.println(treeSet);
}
打印结果:
[Person{name='haha', age=10}, Person{name='cc', age=15}, Person{name='ee', age=12}, Person{name='ee', age=12}]
[Person{name='haha', age=10}, Person{name='ee', age=12}, Person{name='cc', age=15}]
按年龄排序,先开始list中打印出来是乱序的,后来通过treeset按年龄大小正序排列,如果要倒序排只需要将o1和o2调换下位置即可;
实际上这些排序或者是去重的功能在jdk8中已经有了更加高效的方法;通过流的形式
去重:
public static void main(String[] args) {
test collection = new test();
List<Person> list = Lists.newArrayList();
collection.ship(list);
System.out.println(list);
list = list.stream().distinct().collect(Collectors.toList());
System.out.println(list);
}
打印结果:
[Person{name='haha', age=10}, Person{name='cc', age=15}, Person{name='ee', age=12}, Person{name='ee', age=12}]
[Person{name='haha', age=10}, Person{name='cc', age=15}, Person{name='ee', age=12}]
排序:
public static void main(String[] args) {
test collection = new test();
List<Person> list = Lists.newArrayList();
collection.ship(list);
System.out.println(list);
list = list.stream().sorted((a, b) -> a.getAge() - b.getAge()).collect(Collectors.toList());
System.out.println(list);
}
打印结果:
[Person{name='haha', age=10}, Person{name='cc', age=15}, Person{name='ee', age=12}, Person{name='ee', age=12}]
[Person{name='haha', age=10}, Person{name='ee', age=12}, Person{name='ee', age=12}, Person{name='cc', age=15}]
其实list流的处理还有很多,比如统计,分组,过滤。。。。
这些实例我在另外一篇文章中有介绍:
3、Map
Map是按键值对存储的,键不能重复,可以为空,如果put了两个相同的key的话,后进的key的值会覆盖掉原先的值;map也有两个子类HashMap和TreeMap
1)、HashMap是按hash算法排列的,所以存取性能比较好;下面来看一下map遍历的几种方式:
public static void main(String[] args) {
Map<Integer, String> map = Maps.newHashMap();
map.entrySet();/*所有键值对*/
map.keySet();/*所有key*/
map.values();/*所有值*/
/*遍历key*/
for (Integer k : map.keySet()){
int key = k;
String value = map.get(k);
}
/*遍历键值对*/
for (Map.Entry<Integer, String> entry : map.entrySet()){
int key = entry.getKey();
String value = entry.getValue();
}
/*迭代器*/
Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<Integer, String> it = iterator.next();
System.out.println(iterator.next());
}
}
2)、TreeMap的特点就是自动排序,同样性能上和TreeSet一样会收到影响;
public static void main(String[] args) {
Map<Integer, String> treeMap = new TreeMap<Integer, String>();
treeMap.put(4, "ss");
treeMap.put(2, "ss");
treeMap.put(6, "ss");
treeMap.put(1, "ss");
System.out.println(treeMap);/*与treeSet一样存储*/
}
打印结果:
{1=ss, 2=ss, 4=ss, 6=ss}
当我乱序put进去后,打印出来的却是按key从大到小排列的;