List:
List集合类常用的有:ArrayList(连续空间)、LinkedList(不连续空间)
特点:
1)实现List接口的集合类中的元素是有序的,且允许重复。
2) List集合中的元素都对应一个整数型的序号记载其在集合中的位置,可以根据序号存取集合中的元素。
List接口特有方法:
List集合因为支持索引,所以多了很多索引操作的独特api,其他Collection的功能List也都继承了。
ArrayList:
ArrayList底层是基于数组实现的:根据索引定位元素快,增删需要做元素的移位操作。 第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组。
ArrayList是一个可以动态修改的数组,没有固定长度,可以灵活的进行增删改。
ArrayList 继承了 AbstractList ,并实现了 List 接口。
ArrayList特征:查询效率快, 查询某个下标的元素, 只需要计算出下标的地址码,不要一个一个找, 插入,删除效率低, 需要移位
ArrayList常用方法:
添加:add()
删除:remove()
访问:get()
修改:set()
判断:contains()
计算大小:size()
判断数组为空:isEmpty()
查找指定元素下标:indexOf()
package cn.sz.gl.test01;
import java.util.ArrayList;
import java.util.List;
public class Test02 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("zhangsan");
list.add("lisi");
list.add("wangwu");
System.out.println("集合长度:"+list.size());
//list.clear();//清空集合中的所有数据
System.out.println("调用clear方法后,集合长度:"+list.size());
boolean flag = list.contains("lisis");//判断集合中是否包含指定的数据
System.out.println("判断集合中是否包含指定的数据:"+flag);
int index = list.indexOf("wangwu");//用来获取元素保存在list集合中的索引号
System.out.println("获取指定数据的索引号:"+index);
boolean isempty = list.isEmpty();
System.out.println("判断集合是否有元素:"+isempty);
int index2 = list.lastIndexOf("wangwu");
System.out.println("从后往前查找指定的元素,并返回元素的索引号:"+index2);
Object obj = list.remove(2);//用来删除指定位置的元素, 并返回该已经删除的元素
System.out.println("删除第2位的数据后,集合的长度:"+list.size());
System.out.println("删除的元素是:"+obj);
boolean isRemove = list.remove("lisi");//删除指定的元素,并返回是否删除成功
System.out.println("删除lisi后,集合的长度:"+list.size());
System.out.println("删除lisi后,返回值是:"+isRemove);
list.set(0, "zhangsans");//修改指定位置的元素
System.out.println("集合长度:"+list.size());
System.out.println("set之后,元素内容:"+list.get(0));
list.add("111");
list.add("222");
list.add("333");
list.add("xxxx");
list.add("yyyy");
list.add("zzz");
List list2 = list.subList(2, 5);//获取原list集合中的某一部分元素(获取子集),这里包含第2个,但不包含第5个
for (int i = 0; i < list2.size(); i++) {
System.out.print(list2.get(i)+"\t");
}
System.out.println();
System.out.println("***************************************");
Object os [] = list.toArray();//把集合转变为一个数组
for (int i = 0; i < os.length; i++) {
System.out.print(os[i]+",");
}
}
}
LinkedList:
底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了很多首尾操作的特有API。
LinkeList特有方法:
其他方法与上述ArrayList常用方法相同,根据需求来使用两种数组即可
ArrayList和LinkedList的区别:
Set:
Set集合的特点:
-
无序:存取顺序不一致
-
不重复:可以去除重复
-
无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素。
Set集合类常用的有:
HashSet:散列存放(重点)
TreeSet:有序存放(重点)
LinkedHashSet: 有次序
HashSet:
特点:去重、无序,唯一
HashSet 实现了 Set 接口。
HashSet 中的元素实际上是对象,一些常见的基本类型可以使用它的包装类。
HashSet基于HashMap实现,默认构造函数是构建一个初始容量为16,负载因子为0.75 的HashMap。
hashCode()和equals():
怎么判断元素是否存在:
调用元素的hashCode() 方法, 如果不一样, 说明这两个对象不是同一个
如果一样, 调用equlas()方法, 如果返回true, 说明这两个对象是同一个
返回false: 说明这两个对象不是同一个
如果是自定义的类类型, 需要这个类重写hashCode()与equlas()方法
因为hashCode()和equals()方法的返回值共同决定了两个对象是否相等,所以覆写着两个方法时一般要保证两个方法的返回值保证兼容。
重写hashCode()和equals()方法的基本规则:
1、 如果两个对象通过equals()方法比较时返回true,则两个对象的hashCode()方法返回值应该也相等。
2、 对象中用作equals()比较标准的成员变量(属性),也应该参与到hashCode的计算。
LinkedSet:
特点:去重、有序、唯一
根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序
LinkedHashSet集合特点:
底层是一个哈希表(数组+链表/红黑树)+链表,多了一条链表(记录元素的存储顺序),保证元素有序
遍历的时候,LinkedHashSet将会以元素的添加顺序访问集合的元素
LinkedHashSet的方法与它父类HashSet方法是一样的
TreeSet:
TreeSet使用红黑树结构对加入的元素进行排序存放,所以放入TreeSet中元素必须是可“排序”的。
TreeSet可是采用两种方法实现排序:自然排序和定制排序。默认情况,TreeSet采用自然排序。
TreeSet调用调用集合元素的CompareTo()方法,根据该方法的返回值来比较元素之间的大小,然后进行“升序”排列,这种排序方式我们称之为自然排列。
注意:如果想采用自然排序,则要存储的对象所属类必须实现Comparable 接口。该接口只有一个方法public int compareTo(Object obj),必须实现该方法。
compareTo方法的实现规则:
返回 0,表示 this == obj。//则不会添加新对象(this)
返回正数,表示 this> obj //添加到原来对象(obj)的右边
返回负数,表示 this < obj // 添加到原来对的左边
实现例:
public class Student implements Comparable<Student> {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Student").append('[')
.append("name=")
.append(name)
.append(",age=")
.append(age)
.append(']');
return sb.toString();
}
@Override
public int compareTo(Student o) {
//根据年龄升序排序
int rs = this.age - o.age;
if(rs == 0 ){
if(o == this){
return 0;
}else{
return -1;
}
}
return rs;
}
}
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet();
treeSet.add(new Student("张三",21));
treeSet.add(new Student("李四",18));
treeSet.add(new Student("王五",20));
treeSet.add(new Student("李琦",19));
System.out.println(treeSet);
}
}
定制排序:
使用Comparable接口定义排序顺序有局限性:实现此接口的类只能按compareTo()定义的这一种方式排序。
如果需要更加灵活地排序,我们可以自定义(Comparator)比较器,在创建TreeSet集合对象时把我们自定义的比较器传入,则可以TreeSet会按照我们的比较器中定义的规则进行排序。
自定义比较器类,需要实现Comparator接口。Comparator接口只有一个抽象方法需要实现:public int compare(Object a, Object b);
判断规则:
返回 0,表示a == b
返回正数,表示b > b
返回负数,表示a < b
创建TreeSet集合对象时,把自定义比较器对象传入即可,TreeSet会自动按照比较器中的规则进行排序。
实现例:
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Student stu1 = (Student)o1;
Student stu2 = (Student)o2;
//按照年龄的降序排序
return stu2.getAge() - stu1.getAge() ;
}
});
treeSet.add(new Student("张三",21));
treeSet.add(new Student("李四",18));
treeSet.add(new Student("王五",20));
treeSet.add(new Student("李琦",19));
System.out.println(treeSet);
}
}
Map:
Map集合: 存储的key/value键值对
Map: 映射(一一对应), key与value的映射, 一个key对应一个value
Map集合特征:
1) 通过键-值(key-value)对的形式来存储数据
2) Map的实现:HashMap(使用频率最高的),TreeMap,HashTable
3) Map中,key可以为任意类型,但这里建议使用String,value也可以是任意类型
4) Map里面多个value可以是不同类型
5) Map里面key是可以重复的,当key重复时,后存入的数据会覆盖前面的数据
6) Map里面,value可以重复.
7) Map里面的key可以为null,但是只能有一个,多个的时候,后面的会覆盖前面的
8) Map中value可以是null,多个value可以同时为null。
9) Map中的key在底层可以理解为是一个Set
Map常用方法:
-
put(key,value)
如果key不存在,执行添加操作
如果key存在, 执行修改value操作
-
remove(key) 根据key删除key/value对
-
get(key) 根据key获取value
-
containsKey(key) 判断key是否存在, 如果存在,返回true, 不存在: false
-
containsValue(value) 判断value是否存在, 如果存在,返回true, 不存在: false
-
clear() 清空
-
size() 元素个数
-
isEmpty() 判断Map是否是空, true: 是空 , false: 不是空,有元素
-
循环遍历Map
-
entrySet()
-
keySet()
-
values()
-
构造方法:
负载系数: 0.75
ArrayList扩容: 数组长度比size小的时候, 才扩容
Map扩容: 扩容阈值 = 容量 * 负载系统 = 16*0.75 = 12
map的key,value对: 在map中使用一个对象保存, 对象是Node类, Node又是Entry的实现类
HashMap底层原理:
HashMap底层数据结构: 数组+ 链表/红黑树(jdk1.8以及之后)
jdk1.8之前底层数据结构:数组+ 链表
存储原理:
-
它的底层会调用K的hashCode()方法得出hash值。
-
通过哈希表函数/哈希算法,将hash值转换成数组的下标.
-
下标位置上如果没有任何元素,就新创建一个Node节点,并添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾(尾插入)。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
Map使用代码示例:
Map接口常用的实现子类有java.util.HashMap和java.util.Hashtable
import java.util.*;
public class HashMapDemo {
public static void main(String[] args) {
//1.创建HashMap对象,用来存放国家英文简写与国家中文全称
Map map = new HashMap();
//2.往HashMap添加元素(键-值对)
map.put("CN", "中华人民共和国");
map.put("RU", "俄罗斯联邦");
map.put("US", "美利坚合众国");
map.put("FR", "法兰西共和国");
//3.获取key为"CN"对应的值
String value = (String) map.get("CN");
System.out.println(value);
//4.向上集合元素的个数
System.out.println("map集合共有:"+map.size()+"个元素");
//5.判断是否存在"FR"的键
System.out.println("map集合中是否包含FR吗?"+map.containsKey("FR"));
//6 获取Map中键的集合和值得集合
System.out.println("map中key的集合:"+map.keySet());
System.out.println("map中value的集合:"+map.values());
}
}
HashMap的遍历:
目的:遍历出map集合中所有数据
方法一:
1.通过keySet()方法,找到所有key的集合,返回类型是一个Set;
2.通过Iterator迭代器,迭代出Set中的每一个key;
3.通过get(key)方法,根据上一步得到的key,来获取对应的value
Set keys = map.keySet();
Iterator iterator = keys.iterator();
while(iterator.hasNext()){
Object key = iterator.next();
Object val = map.get(key);
}
方法二:
1.通过values()方法,获取map集合中所有的value的集合.返回值类型为Collection(该接口是List和Set的父接口,该类型下有Iiterator迭代器,可以用来迭代)
2.通过Iterator迭代器,迭代出所有的value
Collection values = map.values();
Iterator iterator = values.iterator();
while(iterator.hasNext()){
Object value = iterator.next();
}
方法三:
1.通过entrySet()方法,得到一个Entry对象的集合,这里用Set来装载.
2.通过Set中的迭代器,迭代出每一个Entry对象.
3.针对每一个Entry对象,通过getKey()和getValue()方法,来分别获取到对应的key和value
Set entrySet = map.entrySet();
Iterator iterator = entrySet.iterator();
while(iterator.hasNext()){
Map.Entry entry = (Map.Entry)iterator.next();
Object key = entry.getKey();
Object value = entry.getValue();
}