java 中关于集合类的整理01

本文详细介绍了Java集合框架的各种集合类型,包括List、Set、Map等的实现类与接口,探讨了它们的特点及适用场景,并通过具体示例展示了如何使用这些集合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前看过一些关于Java集合类的内容,但是过段时间不用有些就忘记了,现在整理下以后看也方便,只是给自己当笔记看的~~~~

(转载了一些注明:http://www.cnblogs.com/leeplogs/p/5891861.html)

一般地,我们常用的集合类有这几种:

List结构的集合类:ArrayList类,LinkedList类,Vector类,Stack类

Map结构的集合类:HashMap类,Hashtable类

Set结构的集合类:HashSet类,TreeSet类

Queue结构的集合:Queue接口

 

首先呢,我们来看看为什么要用集合类,这就要说说集合类与数组的关系了。数组(可以存储基本数据类型)是用来存现对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用。

集合(只能存储对象,对象类型可以不一样)的长度可变,可在多数情况下使用。   集合的底层,是如何实现可变长度的,这里我们后面再来分析,。。。

 

一.Java集合框架图可见下图(实线边框的是实现类,折线边框的是抽象类,而点线边框的是接口)


在Java类库中,集合类的基本接口是Collection接口。这个接口有两个基本方法:

public interface Collection<E>
{
   boolean add(E element);
   Iterator<E> iterator();
   ...
}

add()方法就是添加元素了,而Iterator方法用于返回一个实现了Iterator接口的对象。 我们可以使用这个迭代器的对象一次访问集合中的元素。

而Iterator接口包含4个方法:

public interface Iterator<E>
{
   E next();
   boolean hasNext();
   void remove();
   default void forEachRemaning(Consumer<? super E> action);
}

 通过反复调用next方法,可以逐个访问集合中的每个元素。 如果到了集合末尾,next方法将会抛出一个NoSuchElementException.所以在调用next之前需要先调用一下hasNext()方法。

例如:

Collection<String> c  = ...;
Iterator<String> itra = c.iterator();
while(itra.hasNext())
{
  String element = itra.next();
  do something with element...
}

或者用foreach:

for(element:c)
{
   do something with element;
}

 

二. 集合有两个基本接口:  Collection 和  Map

Collection接口是集合类的根接口,Java中没有提供这个接口的直接的实现类。但是却让其被继承产生了两个接口,就是SetListSet中不能包含重复的元素。List是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式。

MapJava.util包中的另一个接口,它和Collection接口没有关系,是相互独立的,但是都属于集合类的一部分。Map包含了key-value对。Map不能包含重复的key,但是可以包含相同的value

 

三.几个具体的接口和实现类

1. List(有序,可重复)

    类似于顺序表,元素会增加到容器中的特定位置,可以采用两种方式访问元素:1.迭代器  2.使用一个整数索引来访问。   后一种方式称为随机访问(random access),因为这样可以按任意顺序访问元素。List 查询数据快,但是插入,删除数据时速度很慢。

    List 总用于随机访问的方法:

void add(int index. E element)
void remove(int index)
E get(int index)
E set(int index, E element)

2.Set(无序,不可重复)

Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。

3.Map(键值对,键唯一,值不唯一)

Map集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。

对比如下:

 

四.具体的集合

 1. LinkedList  链表

在java中,所有的链表实际都是双向链接的(doubly linked), 即每个结点还存放着指向前驱结点的引用。

下面的代码中先是添加了3个元素,然后删去第二个位置的元素:

1         List<Integer> staff = new LinkedList<>();
2         staff.add(10);
3         staff.add(25);
4         staff.add(48);
5         Iterator iter = staff.iterator();
6         int a = (int) iter.next();
7         int b = (int) iter.next();
8         iter.remove();

LinkedList.add方法将对象添加到链表的尾部,但是,我们常常需要将元素添加到链表中间,这时候我们就需要用到迭代器了。

LinkedList类的 ListIteration方法 返回 一个实现了ListIterator接口的迭代器对象。 接下来演示一下越过链表中的第一个元素,在第二个元素之前添加元素。

List<String> staff =new LinkedList<>();
staff.add("A");
staff.add("B");
staff.add("C");
ListInterator<String> iter = staff.listIterator();
iter.next();
iter.add("D");

set方法:

 1         List<String> staff =new LinkedList<>();
 2         staff.add("A");
 3         staff.add("B");
 4         staff.add("C");
 5         ListIterator<String> iter = staff.listIterator();
 6         iter.next();
 7         iter.add("D");
 8         iter.add("E");
 9         String oldValue = iter.next();    返回的上一个元素
10         iter.set("F");
11         System.out.println(oldValue);     //B   ADEFC

get方法:

List<String> staff =new LinkedList<>();
String bb = staff.get(2);
System.out.println(bb);

当然这种方法效率极低,因为这是链表啊,。。

最后,分析下我们为什么要使用链表呢?

因为使用链表可以减少在列表中间插入或者删除元素所付出的代价,如果元素较少,那么完全可以使用ArrayList。 如果需要对集合中的元素进行随机访问,那么就使用ArrayList()或者数组。

四. 具体的集合

2. ArrayList 数组列表

注: ArrayList类 与 Vector类 有什么区别呢?

答:Vector类的所有方法都是同步的,所以说Vector类是线程安全的,所以两个线程可以安全的访问一个Vector对象。 但是,如果只有一个线程访问Vector的话,代码要在同步上花费大量的时间。所以在不需要同步的时候使用ArrayList,而同步的时候使用Vector

 

3.散列集   

首先要知道哈希表这个概念,最常见的是使用“拉链法”来实现的,

左边是一个数组,右边是一个链表,这些链表可以为空。

在Java中,散列表用链表数组实现,每个链表可以看做桶(bucket),要想找到表中对象的位置,就要先计算他的散列码,然后与桶的总数取余,所得到的结果就是保存这个元素的索引。

有时候桶会被占满,这也是无法避免的,这种现象被称为散列冲突。(hash collision)

 1 public static void main(String[] args) {
 2         Set<String> words = new HashSet<>();
 3         long totalTime = 0;
 4         
 5         try(Scanner in = new Scanner(System.in)){
 6             while(in.hasNext()){
 7                 String word = in.next();
 8                 long callTime = System.currentTimeMillis();
 9                 words.add(word);
10                 callTime = System.currentTimeMillis() - callTime;
11                 totalTime +=callTime;
12             }
13         }
14         Iterator iter = words.iterator();
15         for(int i=1;i<20 && iter.hasNext();i++){
16             System.out.println(iter.next());
17         }
18         System.out.println("...");
19         System.out.println(words.size()+"distinct words."+totalTime+"millseconds");
20     }

以ctrl + z 结束输入。

4.数集 

TreeSet类与散列集很相似,但是它比散列集有所改进。数集是一个有序集合。 可以以任意顺序插入到集合中,在对集合进行遍历时,每个值将自动地按照排序后的顺序呈现。

1     public static void main(String[] args) {
2         SortedSet<String> sorter = new TreeSet<>(); //TreeSet implements SortedSet
3         sorter.add("james");
4         sorter.add("hah");
5         sorter.add("wade");
6         for(String s:sorter){
7             System.out.println(s);    //hah  james wade
8         }
9     }             

 

TreeSet 的实现当前使用的是 红黑树。  (关于红黑树以后再细说,。。。)

树的排序必须是全序,也就是说,任意两个元素必须是可比的。 所以这些元素必须实现了 Comparable 接口,或者构造集时必须提供一个Comparator。  下面是一个简单的例子:

//自定义数据类型,并在自定义的数据类型中实现CompareTo方法  
class Teacher implements Comparable {  
    int num;  
    String name;  
  
    Teacher(String name, int num) {  
        this.num = num;  
        this.name = name;  
    }  
  
    public String toString() {  
        return "学号:" + num + " 姓名:" + name;  
    }  
  
    public int compareTo(Object o) {  
        Teacher ss = (Teacher) o;  
        int result = num > ss.num ? 1 : (num == ss.num ? 0 : -1);  
        if (result == 0) {  
            result = name.compareTo(ss.name);  
        }  
        return result;  
    }  
}  
  
public class TreeSetTest {  
    public static void main(String[] args) {          
        Set<Teacher> treeSet = new TreeSet<Teacher>();  
        treeSet.add(new Teacher("zhangsan", 2));  
        treeSet.add(new Teacher("lisi", 1));  
        treeSet.add(new Teacher("wangwu", 3));  
        treeSet.add(new Teacher("mazi", 3)); 
        
        System.out.println(treeSet);//直接输出
        
        Iterator itTSet = treeSet.iterator();//遍历输出
        while(itTSet.hasNext())  
            System.out.print(itTSet.next() + "\t");  
        System.out.println();  
    }   
}  

输出为:

[学号:1 姓名:lisi, 学号:2 姓名:zhangsan, 学号:3 姓名:mazi, 学号:3 姓名:wangwu]
学号:1 姓名:lisi    学号:2 姓名:zhangsan    学号:3 姓名:mazi    学号:3 姓名:wangwu    

 

5.队列与双端队列 

 队列,在尾部添加元素,在头部删除元素。

有两个端头的队列,即双端队列,可以让人们有效地在头部和尾部同时添加或者删除元素,不支持在队列中中间添加元素。

6.优先级队列   

优先级队列(priority queue)中的uansu可以按照任意的顺序插入,却总是按照排序的顺序进行检索。 

即无论何时调用remove()方法,总会获得优先级队列中最小的元素。

优先级队列使用了一个高效的数据结构,

堆: 堆是一个可以自我调整的二叉树,对这个树执行添加(add)和删除(reomve)操作,可以让最小的元素移动到根,而不必花费时间对元素进行排序。

与TreeSet一样,元素必须实现了 Comparable 接口,或者构造集时必须提供一个Comparator。

 1     public static void main(String[] args) {
 2         PriorityQueue<LocalDate> pq = new PriorityQueue<>();
 3         pq.add(LocalDate.of(1906, 12, 9));
 4         pq.add(LocalDate.of(1856, 10, 8));
 5         pq.add(LocalDate.of(1993, 12, 10));
 6         pq.add(LocalDate.of(2004, 11, 15));
 7         
 8         System.out.println("Iterating over eleents...");
 9         for(LocalDate ld:pq)
10             System.out.println(ld);
11         System.out.println("Remove elements...");
12         while(!pq.isEmpty()){
13             System.out.println(pq.remove());
14         }
15     }

结果为:

Iterating over eleents...
1856-10-08
1906-12-09
1993-12-10
2004-11-15
Remove elements...
1856-10-08
1906-12-09
1993-12-10
2004-11-15

7.映射

通常,我们知道某些键的信息,并想要查找与之对应的元素。

映射(map)数据结构就是为此设计的。  映射通常用来存放键/值对。

Java类库中提供了 HashMap 和 TreeMap 的实现。 这两个类都实现了Map的接口。

7.1 HashMap 

 1     public static void main(String[] args) {
 2         Map<String,Integer> staff = new HashMap<>();
 3         staff.put("12-56", 98);
 4         staff.put("26-34", 96);
 5         staff.put("39-48", 84);
 6         staff.put("45-56", 97);
 7         
 8         // print all entries
 9         System.out.println(staff);
10         //remove an entry
11         staff.remove("26-34");
12         //replace an entry
13         staff.put("12-56", 100);
14         //look up a value
15         System.out.println(staff.get("45-56"));
16         // iterate through all entries
17         staff.forEach((k,v) ->
18            System.out.println("key:"+k+",value:"+v));
19     }

最后的输出使用了 lamda 表达式,输出结果为:

{39-48=84, 26-34=96, 12-56=98, 45-56=97}
97
key:39-48,value:84
key:12-56,value:100
key:45-56,value:97

 

HashMap是面试的重点,面试官可能会问道HashMap是怎样构造的等等问题,这些以后再专列复习吧,。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值