Java集合List、Set和Map的区别

来源:互联网 发布:禁入证券市场 知乎 编辑:程序博客网 时间:2024/05/16 15:02

Java集合

1、集合与数组
  Java中对集合的理解是相对于数组而言的。
  数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型)。
  而java集合可以存储和操作数目不固定的一组数据。所有的JAVA集合都位于java.util包中!java集合只能存放引用类型的的数据,不能存放基本数据类型。简单来说就是,数组存放大小固定,类型一样的数据;而集合存放大小不固定,引用类型的数据,不存放基本类型数据。

JAVA集合主要分为三种类型:
(1)Set(集)
(2)List(列表)
(3)Map(映射)

2、Collection 接口
  Collection是最基本的集合接口,声明了适用于java集合(只包括Set和List)的通用方法。Set 和List 都继承了Conllection接口的方法,但是Map不继承。Collection接口的方法:
  boolean add(Object o) : 向集合中加入一个对象的引用
  void clear() : 删除集合中所有的对象,即不再持有这些对象的引用
  boolean isEmpty(): 判断集合是否为空
  boolean contains(Object o) : 判断集合中是否持有特定对象的引用
  Iterartor iterator() : 返回一个Iterator对象,可以用来遍历集合中的元素
  boolean remove(Object o) : 从集合中删除一个对象的引用
  int size() : 返回集合中元素的数目
  Object[] toArray(): 返回一个数组,该数组中包括集合中的所有元素

关于:Iterator() 和toArray() 方法都用于集合的所有的元素,前者返回一个Iterator对象,后者返回一个包含集合中所有元素的数组。Iterator接口声明了如下方法:
  hasNext() : 判断集合中元素是否遍历完毕,如果没有,就返回true
  next() : 返回下一个元素
  remove() : 从集合中删除上一个有next()方法返回的元素。

3、Set(集合):
  Set是最简单的一种集合。集合中的对象不按特定的方式排序,无序,并且没有重复对象。Set接口主要实现了三个类:
  HashSet : HashSet类按照哈希算法来存取集合中的对象,存取速度比较快。
  TreeSet : TreeSet类实现SortedSet接口,能够对集合中的对象进行排序。按照比较结果的升序保存对象。
  HashLinkedSet:按照被添加的顺序保存对象。

(1)Set 的用法:存放的是对象的引用,没有重复对象,如:

Set set=new HashSet();String s1=new String("hello");String s2=s1;String s3=new String("world");set.add(s1);set.add(s2);set.add(s3);System.out.println(set.size());//打印集合中对象的数目为 2。

(2)Set的遍历

Set<String> set = new HashSet<String>();        set.add("a");  set.add("b");  set.add("c");  set.add("d");  set.add("e");         //set.add("e");//不能放入重复数据   /** * 遍历方法一,迭代遍历  */  for(Iterator<String> iterator = set.iterator();iterator.hasNext();){    System.out.print(iterator.next()+" ");  }     System.out.println();  System.out.println("********************");  /**  * 遍历方法二,for增强循环遍历 */  for(String value : set){      System.out.print(value+" ");  }  

  这里Set集合中放入的是String类型,假如我们放入一个自己定义的类实例的时候,比如Person类实例,这时候我们要自己重新hashcode和equal方法,用自己的关键字段来重写,因为当使用HashSet时,hashCode()方法就会得到调用,判断已经存储在集合中的对象hashcode值是否与增加的对象的hash code值一致;如果不一致,直接加进去;如果一致,再进行equals方法的比较,equals方法如果返回true,表示对象已经加进去了,就不会再增加新的对象,否则加进去。

(3)TreeSet
  TreeSet使用元素的自然顺序对元素进行排序,或者根据创建set时提供的Comparator 进行排序,具体取决于使用的构造方法。通俗一点讲,就是可以按照排序后的列表显示,也可以按照自己指定的规则排序。

Set<String> set = new TreeSet<String>();  set.add("f");  set.add("a");  set.add("b");  set.add("c");  set.add("d");  set.add("e");     System.out.println(set);  

输出:[a, b, c, d, e, f]

1)如果让其倒序输出,当然方法很多。这里我采用指定一个规则让他倒序输出:

public class TreeSetTest3 {        public static void main(String[] args) {          Set<String> set = new TreeSet<String>(new MyComparator());          set.add("a");          set.add("b");          set.add("c");          set.add("d");          set.add("e");          set.add("A");          for(Iterator<String> iterator = set.iterator();iterator.hasNext();){            System.out.print(iterator.next()+" ");          }      }  }  class MyComparator implements Comparator<String>{      @Override      public int compare(String o1, String o2) {           return o2.compareTo(o1);//降序排列      }  }  

输出:e d c b a A

2)如果Set集合中放入的是我们自己定义的一个类类型呢?
注意:一定要定义一个排序规则类实现Comparator接口,与上面的方法类似

public class TreeSetTest2 {      public static void main(String[] args) {          Set<Person> set = new TreeSet<Person>(new PersonComparator());        Person p1 =  new Person(10);          Person p2 =  new Person(20);          Person p3 =  new Person(30);          Person p4 =  new Person(40);          set.add(p1);        set.add(p2);        set.add(p3);        set.add(p4);        for(Iterator<Person> iterator = set.iterator();iterator.hasNext();){            System.out.print(iterator.next().score+" ");        }    }}class Person{    int score;    public Person(int score){        this.score = score;    }    public String toString(){        return String.valueOf(this.score);    }}class PersonComparator implements Comparator<Person>{    @Override    public int compare(Person o1, Person o2) {        return o1.score - o2.score;    }}

输出:10 20 30 40

2、List
  元素是有序的(怎么存的就怎么取出来,顺序不会乱),元素可以重复,因为该集合体系有索引。List是一个接口,不能实例化,需要实例化一个ArrayList或者LinkedList。
  List myList = new ArrayList();
  使用myList.add(任何对象);就可以进行添加了;取值的时候myList.get(索引);取出来的值都是Object,使用时需要类型转换。
  List接口实现的类:ArrayList(实现动态数组),Vector(实现动态数组),LinkedList(实现链表), Stack(实现堆栈)
  ArrayList:按照插入的顺序保存元素,由数组实现的List。长于随机访问元素,在list中间插入和删除元素时较慢。
  LinkedList:按照插入的顺序保存元素,相当于链表。插入和删除元素较快,对于随机访问较慢。
  Array.asList():该方法接受一个数组或者是一个逗号分隔的元素列表(使用可变参数),并将其转换为一个list对象。

(1)List遍历

//从List对象中取值的三种方法List<String> list = new ArrayList<String>();  list.add("a");  list.add("b");  list.add("c");  list.add("c");//可添加重复数据  //遍历方法一  //用Iterator迭代器取值,效率一般Iterator<String> iter = list.iterator(); while(iter.hasNext()){      iter.next();      //System.out.println(iter.next());  }//遍历方法二  for(String value : list){      System.out.println(value);  }  //遍历方法三  for(int i=0;i<list.size();i++){      System.out.println(list.get(i));  }  

三种遍历的比较分析:
方法一遍历:
  执行过程中会进行数据锁定, 性能稍差, 同时,如果你想在循环过程中去掉某个元素,只能调用iter.remove()方法。
方法二遍历:
  内部调用第一种
方法三遍历:
  内部不锁定, 效率最高, 但是当写多线程时要考虑并发操作的问题
  List接口的两种主要实现类ArrayList和LinkedList都可以采用这样的方法遍历

扩展

附:关于ArrayList与LinkedList的比较分析:
1)ArrayList底层采用数组实现,LinkedList底层采用双向链表实现。
2)当执行插入或者删除操作时,采用LinkedList比较好。
3)当执行搜索操作时,采用ArrayList比较好。
说白了,就是数据结构中的顺序存储和链式存储

3、Map
(1)Map的一般用法
1)声明一个Map :

Map<String, String> map = new HashMap<String, String>();

2)向map中放值 ,注意: map是key-value的形式存放的,如:

map.put("sa","dd");//Map中元素存放是无序的

3)从map中取值 :

String str = map.get("sa").toString();//结果是:str = "dd'

(2)Map的遍历大体有3种:
1)遍历Map.entrySet():它的每一个元素都是Map.Entry对象,这个对象中,放着的就是Map中的某一对key-value;
2)遍历Map.keySet():它是Map中key值的集合,我们可以通过遍历这个集合来读取Map中的元素;
3)遍历Map.values():它是Map中value的集合,我们可以直接通过这个集合遍历Map中的值,却不能读取key。

(3)遍历Map的四种方法:

public static void main(String[] args) {  Map<String, String> map = new HashMap<String, String>();      map.put("1", "value1");      map.put("2", "value2");      map.put("3", "value3");      //第一种:普遍使用,二次取值      //通过Map.keySet遍历key和value:      for (String key : map.keySet()) {          System.out.println("key= "+ key + " and value= " + map.get(key));      }      //第二种      //通过Map.entrySet使用iterator遍历key和value:      Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();      while (it.hasNext()) {          Map.Entry<String, String> entry = it.next();          System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());      }      //第三种:推荐,尤其是容量大时      //通过Map.entrySet遍历key和value      for (Map.Entry<String, String> entry : map.entrySet()) {          System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());      }      //第四种      //通过Map.values()遍历所有的value,但不能遍历key      for (String v : map.values()) {          System.out.println("value= " + v);      } }

(4)HashMap注意事项:
1)HashMap底层维护一个数组,我们向HashMap中所放置的对象实际上是存储在该数组当中,用来快速访问。
2)当向HashMap中put一对键值时,它会根据key的hashCode值计算出一个位置,该位置就是此对象准备往数组中存放的位置。
3)TreeMap:按照比较结果的升序保存键值。
4)LinkedHashMap:按照被添加的顺序保存键值对.

(5)HashMap应用举例:控制台输入一句英语,简单统计各个单词出现的次数

/** * 统计一句英语的简单统计各个单词出现的次数 */  public class MapTest3 {      public static void main(String[] args) {          Scanner sc = new Scanner(System.in);          System.out.println("请输入一句英语,单词间用空格隔开:");          String sentence = sc.nextLine();          String[] arr = sentence.split(" ");          //key代表着单词,value代表着次数          Map<String, Integer> map = new HashMap<String, Integer>();          for (int i = 0; i < arr.length; i++) {              if (!map.containsKey(arr[i])) {                  map.put(arr[i], 1);              } else {                  // 说明map中,存在该元素                  int num = map.get(arr[i]);                  map.put(arr[i], ++num);              }          }          System.out.println("统计单词出现的个数,结果如下:");          Set<String> set = map.keySet();          for (Iterator<String> iterator = set.iterator(); iterator.hasNext();) {              String key = iterator.next();              Integer value = map.get(key);              System.out.println(key + "=" + value);          }      }  }

输出结果:
请输入一句英语,单词间用空格隔开:
hello world j a va ja va
统计单词出现的个数,结果如下:
hello=1
world =1
j=1
a=1
va=2
ja=1

0 0