集合类就是用于存储多个数据的类 在Java基础中我们学习了数组,而数据时可以存储多个数据的,为什么还要使用集合?
用于存放多个数据
数组中的数据的数据类型是相同的
数组的长度固定
数组的操作需要开发人员自己定义相关操作算法
集合类中可以存放多个数据
集合类中存放的数据的类型的任意类型(内部类型为Object类型,所以可以存放任意类型)
集合类的长度都是可变的
集合类中提供了关于这类集合的常用操作方法,开发人员可以通过这些方法实现对集合的常见操作
集合类不是一个类,而是一套接口和类的统称
Java中的集合类根据存储方式不同分为两大类集合
基于Collection接口的线性
集合
Collection接口下有两个子接口,分别对应不同的线性集合
1.List接口的特点
1.有序的集合(进入到集合中顺序) 2.可以存放重复数据的集合
List接口的的实现类:
1.ArrayList 2.LinkedList 3.Vector
2.Set接口
1.无序的集合(不保证集合中元素的顺序) 2.不允许存放重复数据的集合
Set接口的实现类: 1.HashSet 2.TreeSet
基于Map接口的key-value
映射对集合
ArrayList底层是基于动态数组实现的
ArrayList的特点
1.ArrayList在使用时,查找其中的元素效率是比较高的,数组有下标,可以通过下标直接锁定到一个元素
ArrayList在插入或移除元素时效率低(内存中要移位)
ArrayList常用API
创建ArrayList对象
//创建ArrayList集合类对象 ArrayList arrayList = new ArrayList();
add(element):向ArrayList的尾部追加一个元素
//向ArrayList的尾部追加元素 arrayList.add("aaa"); arrayList.add(20); arrayList.add('a'); arrayList.add(true); arrayList.add(20.5); 3.add(index,element):向集合中的某个位置插入一个元素 //向ArrayList的某个位置插入元素 arrayList.add(2,"str");
4.get(index):根据下标获得该下标对应的元素,默认返回Object类型(根据自己的需要转换具体类型)
//根据下标获得一个元素 String str= (String) arrayList.get(0); System.out.println(str);
5.remove(element|index):如果参数为对象类型,则根据内容移除,如果参数为int类型的基本类型则根据下标移除
//移除元素 arrayList.remove("aaa"); System.out.println(arrayList); //如果参数为int类型,则根据下标移除,如果要移除的内容为整数则需要使用Integer类型删除 arrayList.remove(new Integer(3)); ystem.out.println(arrayList);
6.遍历ArrayList集合中的所有元素
//遍历List集合中的所有元素 //使用传统for循环遍历 for(int i=0;i
基于List接口的实现类LinkedList
LinkedList的特点
LinkedList底层是基于链表实现
1.插入或删除元素时效率高 2.查询及遍历元素时效率低
LinkedList常用PAI
add(element):尾部添加
addFirst(element):首部插入
addLast(element):尾部插入
add(index,element):指定下标位置插入元素
push(element):入栈
pop():出栈
toArray():将列表转换为数组
基于List接口的实现类Vector
Vector的特点
1.Vector的底层也是基于动态数组实现 2.Vector中提供的操作和ArrayList基本相同
ArrayList和Vector的区别
相同点:ArrayList和Vector底层都是基于动态数组实现,而且提供了相近的API
不同点: (1) ArrayList默认创建长度为0的数组,而Vector创建的长度为10的数组 (2) Vector是线程安全的,而ArrayList是非线程安全的,在并发情况下建议使用Vector 我们可以通过外部手段让ArrayList也是线程安全的
基于Set接口的实现类HashSet
HashSet的特点 :
1.底层基于Map集合的实现
2.不能存放重复数据
3.集合中的元素不保证顺序
4.Set集合无法从集合中直接获取某一个元素
5.Set集合没有下标
HashSet常用API 1.add(element):向集合中添加一个元素 2.iterator():遍历集合中的所有元素
//遍历集合中元素 Iteratoriterator = hashSet.iterator(); //循环遍历集合中的每个元素 while(iterator.hasNext()){//检测集合中是否存在要迭代的数据,true表示存在 String str = iterator.next();//获取一个元素 System.out.println(str); }
3.通过foreach循环遍历集合中所有元素
//使用foreach遍历集合中的所有元素 for(String str : hashSet){ System.out.println(str); }
4.使用foreach方法遍历集合中的元素
//通过foreach方法遍历集合中的所有元素 hashSet.forEach(System.out::println);
基于Set接口的TreeSet实现
TreeSet是基于树状结构的Set集合,该集合可以排序,被称为可排序的Set集合
TreeSet集合的特点 1.TreeSet是一个有序的Set集合 2.TreeSet中不能存放重复数据 3.在TreeSet中存储的元素必须为可排序的元素(实现了比较器接口的对象),如果存储的元素为不可排序的元素则会报异常(ClassCastException)
基于key-value(键值对)的Map集合
Map集合中存储的元素为一个key对应一个value
1.key不允许重复,默认情况下key是Object类型,可以存放任意类型的数据 2.value是允许重复,默认情况下value是Object类型,可以存放任意类型的数据 3.Map中允许存在null的key(只能出现一次)和null的value
基于Map接口的实现类HashMap
HashMap中不允许存放重复key,如果新添加的key已存在,则使用新的value替换原有的value值
HashMap的常用API
1.put(key,val):向Map集合中添加一对key-value 2.get(key):根据key获得对应的value 3.remove(key):根据key移除Map集合中的一个元素 4.size():获得集合中元素的数量 5.keySet():获得Map集合中所有的key,返回一个包含所有key的set集合
Mapmap = new HashMap (){{ put("key1","val1"); put("key2","val2"); put("key3","val3"); put("key4","val4"); put("key5","val5"); }}; //获得所有的key Set keySet = map.keySet(); //使用keySet遍历Map集合 Iterator it = keySet.iterator(); while(it.hasNext()){ String key = it.next(); String value = map.get(key); System.out.println(key+"<---->"+value); }
6.values():获得Map集合中所有的value,返回一个Collection集合 7.entrySet():获得Map集合中每个元素的Entry集合对象,返回Set集合
for (Map.Entryentry : map.entrySet()){ System.out.println(entry.getKey()+"<--->"+entry.getValue()); }
Map集合中的key不能重复,如果想Map添加一个新元素,Map集合如何判定该元素在集合中是否存在?
基于Map接口的TreeMap实现类
TreeMap和TreeSet一样都是一个可排序的集合 TreeMap中根据key进行排序的 进入到TreeMap中的元素(key)必须为可排序的元素(key) ###equals方法 ==也是用于判断两个对象是否相等:用于判断两个对象是否为同一个对象的 equals方法用于判断两个对象的值是否相等
String s1 = "abc"; String s2 = "abc"; //s1和s2两个变量都指向“abc”字符串对象,他们两个是同一个对象 System.out.println(s1 == s2); /** * Java中每次使用new关键字创建对象时,在JVM的堆区都会自动创建一个新对象 * 只不过两个对象的值都是"abc"字符串 * 这两个对象不是同一个对象,但他们的值是相等 * 所以“==”的结果为false,他们两个不是同一个对象 * 如果要判断两个对象的值是否相等使用equals方法 */ String str = new String("abc"); String str1 = new String("abc"); System.out.println(str == str1);//false System.out.println(str.equals(str1));
equals方法在任意对象中都存在,该方法在Object类中定义的,他们默认定位为
public boolean equals(Object obj) { return this == obj; }
从Object类中的源码可以看出,equals方法默认的定义为判断两个对象是否为同一个对象的 所以为了能够判断两个对象的值是否相等,我们在自己定义的实体类中都会重写该方法 String重写equals方法,JDK中大多数类都重写了该方法...
hashCode方法
hashCode方法在任意类中都存在,该方法也是在Object类中定义的 hashCode方法用于获得当前对象所对应的内存地址的hash码 如果两个对象的hash相等,则表示当前的两个对象肯定为同一个对象(默认情况) 开发人员可以根据实际需要重写hashCode,重写后不同对象的hashCode就有可能相等
在开发中一般会重写equals方法和hashCode方法以改变他们的默认行为
Map集合如何判断新添加的元素的key在集合中是否存在
1.先判断hashCode是否相等,如果hashCode不相等则认为没有相同的对象,直接将新元素添加到map集合中 2.如果hashCode的值存在相等的,则无法确定是否存在相同对象,进而继续判断equals方法,如果equals返回值为true,则认为存在相等元素 使用新元素替换原有的元素,如果equals判断是不相等,则认为不存在相同对象直接将新元素添加到map集合中
比较器接口
比较器是用于定义比较规则,有了比较规则后,就可以对这些数据按照比较规则进行排序 Java中定义比较规则的方式有两种:
(1) 实现Comparable接口:Comparable在java.lang包下 - Comparable用于实现对象的默认比较规则,默认比较规则只有一种 - Comparable中存在一个compareTo方法,该方法用于定义比较规则 - 方法的返回值为正整数表示当前对象大于比较对象 - 方法的返回值等于0两个对象相等 - 方法的返回值为负整数表示当前对象小于比较对象
@Override public int compareTo(User user) { return this.userId - user.getUserId(); }
(2) 实现Comparator接口:Comparator在java.util包下 - Comparator用于定义对象的扩展比较规则的,可以定义多个 - Comparator接口中有一个定义比较规则的方法compare(obj1,obj2) - 方法的返回值为正整数表示obj1大于obj2 - 方法的返回值等于0两个对象相等 - 方法的返回值为负整数表示obj1小于obj2
/** * 使用内部类定义扩展规则 * 1.根据积分升序排序 */ static class sortByScoreASC implements Comparator{ @Override public int compare(User user1, User user2) { return user1.getUserScore() - user2.getUserScore(); } } /** * 2.根据积分降序排序 */ static class sortByScoreDESC implements Comparator { @Override public int compare(User user1, User user2) { return user2.getUserScore() - user1.getUserScore(); } } /** * 2.根据学号降序排序 */ static class sortByUserIdDESC implements Comparator { @Override public int compare(User user1, User user2) { return user2.getUserId() - user1.getUserId(); } } //调用 TreeSet users = new TreeSet<>();//使用user对象中的默认排序规则进行排序 //使用User内定义的内部类指定排序规则 TreeSet users = new TreeSet<>(new User.sortByUserIdDESC()); //使用匿名内部类定义排序规则 TreeSet users = new TreeSet<>(new Comparator () { //使用匿名内部类实现比较器接口 @Override public int compare(User user1, User user2) { return user1.getRegDate().compareTo(user2.getRegDate()); } });