Java 集合框架

目录

集合的继承实现关系: 

Collection接口

Iterator迭代器

 List接口

ArrayList集合

LinkedList

 Set

LinkedHashSet:

TreeSet:

Map接口:

HashMap:,v>

LinkedHashMap:,v>

Map集合遍历键找值方式:

一、键找值方式:即通过元素中的键,获取键所对应的值。

二、Map集合遍历键值对方式

Collections集合工具类 Arrays  


集合的继承实现关系: 

Collecton接口常用的子接口有:List接口、Set接口

List接口常用的子类有:ArrayList类、LinkedList类

Set接口常用的子类有:HashSet类、LinkedHashSet类

List允许有重复的元素,有序。

Set不予许有重复元素,无序。


Collection接口

集合中的顶层接口,它中定义的所有功能子类都可以使用,是共性的功能,是集合中所有实现类必须拥有的方法。

Collection接口的基本方法:

创建集合的格式:

方式1:Collection<元素类型> 变量名 = new ArrayList<元素类型>();

方式2:Collection 变量名 = new ArrayList();

方式1创建的集合,只能存储<>中指定的元素类型,该方式为常用方式

方式2创建的集合,集合的元素类型默认为Object类型,即任何类型的元素都可以存储。

Iterator迭代器

Collection集合元素的通用获取方式:

在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。

这种取出方式专业术语称为迭代

集合中把这种取元素的方式描述在Iterator接口中。

所以可以看到Collection和Map都实现了Iterator接口。

Iterator接口的常用方法如下:

  • hasNext()方法:用来判断集合中是否有下一个元素可以迭代。如果返回true,说明可以迭代。
  • next()方法:用来返回迭代的下一个元素,并把指针向后移动一位。

在Collection接口描述了一个抽象方法iterator方法,所有Collection子类都实现了这个方法,并且有自己的迭代形式。

 for each遍历(增强for循环)本质上也是迭代器

迭代器的并发修改异常 java.util.ConcurrentModificationException
就是在遍历的过程中,使用了集合方法修改了集合的长度,不允许的
Iterator<String> it = list.iterator();
   while(it.hasNext()){
     String s = it.next();
     //对获取出的元素s,进行判断,是不是有"abc"
    // 有就插入一个ABC
     if(s.equals("abc")){
        list.add("ABC");
     }
     System.out.println(s);
   }

运行上述代码发生了错误 java.util.ConcurrentModificationException这是什么原因呢?

在迭代过程中,使用了集合的方法对元素进行操作。导致迭代器并不知道集合中的变化,容易引发数据的不确定性。

并发修改异常解决办法:在迭代时,不要使用集合的方法操作元素。

那么想要在迭代时对元素操作咋办?通过ListIterator迭代器操作元素是可以的,ListIterator的出现,解决了使用Iterator迭代过程中可能会发生的错误情况。但是仅限于删除remove

public void ttt() {
   List<String> list = new ArrayList<String>();
   list.add("1");
   list.add("2");
   list.add("3");
   list.add("4");
   list.add("5");
   for (String item : list) {
     if (item.equals("3")) {
        System.out.println(item);
        list.remove(item);
     }
   }
   System.out.println(list.size());
}
// 遍历的时候移除使用Iterator里面的remove方法。
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
   String data = (String) iterator.next();
   if (data.equals("3")) {
     // 不管在foreach还是Iterator遍历过程中都不允许使用list改变长度
      // 如果是移除元素,可以使用Iterator里面的remove,但是对于添加
      // Iterator就没有提供,可以参考ListIterator
     iterator.remove();
     System.out.println(data);
   }
}
System.out.println(list.size());

 // 不管在foreach还是Iterator遍历过程中都不允许使用list改变长度,如果是移除元素,可以使用Iterator里面的remove,但是对于添加Iterator就没有提供


 List接口

特点(也是所有实现类的特点):

1、它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。

2、它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。

3、 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。

List接口的常用子类有:

ArrayList集合

LinkedList集合

ArrayList集合

常用API

1、增加元素方法

     add(Object e):向集合末尾处,添加指定的元素

     add(int index, Object e):向集合指定索引处,添加指定的元素,原有元素依次后移

2、删除元素删除

     remove(Object e):将指定元素对象,从集合中删除,返回值为被删除的元素

     remove(int index):将指定索引处的元素,从集合中删除,返回值为被删除的元素

3、替换元素方法

     set(int index, Object e):将指定索引处的元素,替换成指定的元素,返回值为替换前的元素

4、查询元素方法

     get(int index):获取指定索引处的元素,并返回该元素

Vector:

Vector集合数据存储的结构是数组结构,为JDK中最早提供的集合。Vector中提供了一个独特的取出方式,就是枚举Enumeration,它其实就是早期的迭代器。此接口Enumeration的功能与 Iterator 接口的功能是类似的。Vector集合已被ArrayList替代。枚举Enumeration已被迭代器Iterator替代。

Vector & ArrayList比较

相同点:

Vector与ArrayList本质上都是一个Object[] 数组,都实现了List这个接口

不同点:

1)Vector是线程安全的集合类,ArrayList并不是线程安全的类。Vector类对集合的元素操作时都加了synchronized,保证线程安全。

2)Vector与ArrayList的扩容并不一样,Vector默认扩容是增长一倍的容量,Arraylist是增长50%的容量。ArrayList就有利于节约内存空间。

Vector无论查询还是增删都很慢,所以被ArrayList替代了。

LinkedList

LinkedList集合数据存储的结构是链表结构。方便元素添加、删除的集合。实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法.

public void test() {
   LinkedList<String> link = new LinkedList<String>();
   //添加元素
   link.addFirst("abc1");
   link.addFirst("abc2");
   link.addFirst("abc3");
   //获取元素
   System.out.println(link.getFirst());
   System.out.println(link.getLast());
   //删除元素
   System.out.println(link.removeFirst());
   System.out.println(link.removeLast());
   
   while(!link.isEmpty()){ //判断集合是否为空
     System.out.println(link.pop()); //弹出集合中的栈顶元素
   }
}

 Set

Set中元素无序不重复

HashSet:

无序:HashSet集合不能保证的迭代顺序与元素存储顺序相同。

不重复:HashSet集合,采用哈希表结构存储数据,保证元素唯一性的方式依赖于两个方法:hashCode()与equals()方法。

散列表(Hash table,也叫哈希表):
是根据关键码值(Key value)而直接进行访问的数据结构。
HashSet元素不能重复,如何实现:

当向哈希表中存放元素时,需要根据元素的特有数据结合相应的算法,这个算法其实就是Object类中的hashCode方法。由于任何对象都是Object类的子类,所以任何对象有拥有这个方法。即就是在给哈希表中存放对象时,会调用对象的hashCode方法,算出对象在表中的存放位置,这里需要注意,如果两个对象hashCode方法算出结果一样,这样现象称为哈希冲突这时会调用对象的equals方法,比较这两个对象是不是同一个对象,如果equals方法返回的是true,那么就不会把第二个对象存放在哈希表中,如果返回的是false,就会把这个值存放在哈希表中。

hashCode()与 equals() 的相关规定:

1、如果两个对象相等,则 hashcode 一定也是相同的

2、两个对象相等,两个 equals() 方法返回 true

3、两个对象有相同的 hashcode 值,它们也不一定是相等的

因为HashSet默认是根据变量的地址判断是不是已经加入HashSet了。

这样的话:

Student  stu1 = new Student(1, "张三", 20);

Student  stu2 = new Student(1, "张三", 20);

stu1和stu2都能够加入HashSet里面,因为他们的地址不一样,但是这其实是同一个Student,只是分别通过不同的方式new出来,如果stu1和stu2都能够加入的话,那么这个学生就在HashSet里面重复了。

所有的类都继承自Object类,Object类里面有hashCode和equal这两个方法,

 HashSet调用add方法时候判断这个对象有没有已经在Set里面就是根据equal方法

解决方法就是:我们自己来判断是不是已经存在,选择你要比较的属性,覆写hashCode和equal方法

自定义类型(如果要使用HashSet,必须手动实现hashCode和equals):
能不能放进Set里面,首先看hashCode值是不是一样,如果不一样就可以放进去,
如果hashCode值一样,再比较equals是不是一样,如果不一样就可以放进去

LinkedHashSet:

我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序?

在HashSet下面有一个子类LinkedHashSet,它是链表和哈希表组合的一个数据存储结构。

public void test4() {
   Set<String> set = new LinkedHashSet<String>();
   set.add("bbb");
   set.add("aaa");
   set.add("abc");
   set.add("bbc");
   Iterator it = set.iterator();
   while (it.hasNext()) {
     System.out.println(it.next());
   }
}

TreeSet:

Java中的TreeSet是Set的一个子类,TreeSet集合是用来对象元素进行排序的,同样他也可以保证元素的唯一。

那TreeSet为什么能保证元素唯一,它是怎样排序的呢?

public void test5() {
   TreeSet<Student> treeSet = new TreeSet<>();
    treeSet.add(new Student(1, "张三", 23));
    treeSet.add(new Student(2, "李四", 13));
    treeSet.add(new Student(3, "周七", 13));
    treeSet.add(new Student(4, "王五", 43));
    treeSet.add(new Student(5, "赵六", 33));
   
    System.out.println(treeSet);
}

执行结果:

出错,会抛出一个异常:java.lang.ClassCastException: com.situ.mall.test.Student cannot be cast to java.lang.Comparable

显然是出现了类型转换异常。原因在于我们需要告诉TreeSet如何来进行比较元素,如果不指定,就会抛出这个异常

所以我们需要指定比较规则:

需要在自定义类(Student)中实现```Comparable```接口,并重写接口中的compareTo方法 

几种重写方法:

@Override
   public int compareTo(Student o) {
       return 0;  //当compareTo方法返回0,元素值每次比较,都认为是相同的元素
       return >0;  //当compareTo方法返回值正数,元素值每次比较,都认为新插入的元素比上一个元素大,读取时就是正序排列的
       return <0; //当compareTo方法返回值负数,元素值每次比较,都认为新插入的元素比上一个元素小,读取时就是倒序排列的
   }
}

按照年龄来排序,年龄相同按照名字排序:

public int compareTo(Student o) {
    int num = this.age - o.age;                //年龄是比较的主要条件
    return num == 0 ? this.name.compareTo(o.name) : num;//姓名是比较的次要条件
}

按照姓名长度排序:

public int compareTo(Student o) {
    int length = this.name.length() - o.name.length();              //比较长度为主要条件
    int num = length == 0 ? this.name.compareTo(o.name) : length;    //比较内容为次要条件
    return num == 0 ? this.age - o.age : num;                        //比较年龄为次要条件
}

Map接口:


1、Collection中的集合,元素孤立存在。向集合中存储元素采用一个个元素的方式存储。

2、Map中的集合,元素成对存在。每个元素由键与值两部分组成,通过键可以找对所对应的值。

3、Collection中的集合称为单列集合,Map中的集合称为双列集合

4、需要注意的是,Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值。

(Key可以为null但是只能有一个为null,值可以多个为null)

5、Map中常用的集合为HashMap集合、LinkedHashMap集合

HashMap<K,V>:


存储数据采用的哈希表结构,元素的存取顺序不能保证一致

由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。(存放自定义类的时候重写,API中的类不需要)

LinkedHashMap<K,V>:

HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致

通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。

Map集合遍历键找值方式:


一、键找值方式:即通过元素中的键,获取键所对应的值。


1.获取Map集合中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。

 

2.遍历键的Set集合,得到每一个键

3.根据键,获取键所对应的值

二、Map集合遍历键值对方式

键值对方式:即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值。

1.获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。

2.遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象

3.通过键值对(Entry)对象,获取Entry对象中的键与值。

注意:Map集合不能直接使用迭代器或者foreach进行遍历。但是转成Set之后就可以使用了。


Collections集合工具类 Arrays  

Collections类常用方法总结 - Eason_S - 博客园

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值