集合
概念:当我们需要对数据进行保存时,数据的类型可能多种多样,于是就有了数据结构,在java中对数据结构的实现就是我们的集合
1.可以动态保存多个对象,使用方便
2.提供一些方便操作的方法,增加,删除,查找
集合API
集合体系概述:Java集合框架是由一些接口,抽象类和具体类组成的,都位于Java.util包中
Collection接口
在Collection接口中定义了一些集合共有的方法
下面是用代码进行总结的这些方法
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
Collection<String> co = new ArrayList<String>();
c.add("asd");//增加单个元素
c.add("b");
c.add("c");
//c.clear();//全部删除
System.out.println(c.remove("b"));//删除指定元素,返回值为boolean类型
System.out.println(c.contains("a"));//查找指定元素,返回值为bolean类型
System.out.println(c.size());//长度
System.out.println(c.isEmpty());//判断是否为空
co.add("zxc");
co.add("c");
c.addAll(co);//将co中所有元素加到c中
System.out.println(c);
//c.removeAll(co);
//System.out.println(c);//删除指定集合,不包含时删除共有元素
System.out.println(c.containsAll(co));//查找指定集合,返回值为bolean类型
}
List集合
1.List接口中元素有序(添加顺序和取出顺序一致)且可重复
2.List接口中每个元素都有其对应的顺序索引
List接口中的一些方法:
public static void main(String[] args) {
List list = new ArrayList();
list.add("a");//添加元素
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("a");
list.add(0, "z");//在指定位置添加元素
System.out.println(list.get(2));//获取指定位置的元素
System.out.println(list.indexOf("a"));//返回指定元素在集合中首次出现的位置
System.out.println(list.lastIndexOf("a"));//返回指定元素最后一次出现在集合中的位置
list.set(0, "x");//将指定位置上元素进行替换
System.out.println(list);
list.remove(0);//删除指定位置上的元素
System.out.println(list);
System.out.println(list.subList(0, 4));//截取指定区间的元素,左闭右开
}
List三种遍历方式:
for循环:
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
arrayList.add("e");
arrayList.add("a");
arrayList.add("b");
for (int i = 0; i < arrayList.size(); i++) {
System.out.println(arrayList.get(i));
}
}
}
增强for:
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList();
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
arrayList.add("e");
arrayList.add("a");
arrayList.add("b");
for(String item : arrayList){
System.out.println(item);
}
}
Iterator迭代:
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList();
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
arrayList.add("e");
arrayList.add("a");
arrayList.add("b");
System.out.println(arrayList);
Iterator<String> iterator = arrayList.iterator();
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
}
}
ArrayList实现类
arrayList底层原理是数组,是线程不安全的,但效率高
扩容机制:当创建一个ArrayList对象时,若使用无参构造时,当添加第一个元素时,将自动扩容为10,如果不能满足时,则会在当前容量下扩容1.5倍;若使用无参构造时,开始给定一定的容量的话,在容量不能满足的情况下,就会在当前容量的基础上扩容1.5倍
LinkedList实现类
LinkedList底层实现了双向链表和双端队列的特点,可以添加任意元素,可包括null,线程不安全没有实现同步
Vector实现类
Vector底层也是对象数组,是线程同步的,也就是线程安全的,但效率不高因为带有synchronized,在开发过程中,考虑到线程安全时,考虑使用Vector
扩容机制:如果是无参构造时,默认为10,满后则按当前容量的2倍进行扩容;若果是有参构造,指定大小,每次直接按2倍进行扩容
Set接口
Set中所存储的元素是不能重复的,最多包含一个null
Set中元素是无序的,取出和添加的顺序是不一致的,没有索引
Set接口中的一些方法:由于Set接口继承了Collection接口,所以常用方法和Collection接口中的一样
Set接口的遍历方式与Collection接口中的遍历也是一样的可以通过,增强for,迭代器,但是不能用索引来获取
HashSet
HashSet实现了Set接口,实际上是HashMap
可以存放null值,但只有一个,元素无序,取决于hash后再决定索引
TreeSet
当使用无参构造器创建TreeSet对象时,他仍然是无序的
当使用它的有参构造器时(Comparator),可以指定排序规则
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<Student> treeSet = new TreeSet();
treeSet.add(new Student("小明", 12458));
treeSet.add(new Student("小红", 12465));
treeSet.add(new Student("小白", 12452));
treeSet.add(new Student("小黑", 12450));
treeSet.add(new Student("小明", 12451));
System.out.println(treeSet);
}
}
class Student implements Comparable<Student>{
private String name;
private int id;
public Student(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
@Override
public int compareTo(Student o) {
//return this.name.compareTo(o.name);
return this.id-o.id;
}
}
Map接口
Map接口与Collection接口并列存在是双列的就有一对键值对(K-V)
Map 中的Key是不可以重复的,Value可以重复.其中Key可以为null,但只能有一个,而Value也可以为null,但是可以有多个
常用String作为Map中的"Key"
Key和Value之间存在单向一对一关系,通过Key可以找到对应的Value
常用方法:
public static void main(String[] args) {
HashMap map = new HashMap();
map.put(10, "zz");//添加元素
map.put(15, "bb");
map.put(6, "kk");
map.put(23, "oo");
map.put(10, "zzzz");
System.out.println(map.isEmpty());//判断是否为空
System.out.println(map.remove(6));//删除指定的键,返回对应的值
System.out.println(map.size());//返回键值对数量
System.out.println(map.containsKey(15));//查找指定键是否存在
System.out.println(map.containsValue("bb"));//查找指定值
System.out.println(map.get(23));//获取指定键对应的值
System.out.println(map.hashCode());
map.replace(23, "ttt");//替换指定键所对应的值
System.out.println(map);
}
HashMap,TreeMap,Hashtable都实现Map接口
HashMap | TreeMap | Hashtable | |
---|---|---|---|
为null的键 | 可以存储一个 | 不能 | |
排序 | 无序 | 实现Comparable接口 | 无序 |
线程安全 | 不安全 | 安全 |
ArrayList添加元素的过程及扩容机制
ArrayList是List接口的一个实现类,他是一个根据需求而动态增长的数组.在Java中数组的标准长度是在创建时就定义好的,一旦给定就无法更改,有时我们需要一些动态的数组来存储数据,此时就可以使用ArrayList,但他的线程不是安全的,它的存储是通过添加的顺序进行存放数据
ArrayList扩容是在调用add()方法时,调用ensureCapacityInternal()来扩容的,通过判断是否需要扩容,扩容的话调用扩容的关键方法是grow()方法,空间扩至原来的1.5倍
我们可以看出其实就是通过判断新的数组的size,然后将原来的数组复制到新的数组中去
HashMap的底层实现原理
HashMap是使用默认长度为16数组加链表的形式存储的,每个数组中存储着链表
使用put方法添加元素时,首先会调用HashCoede方法,判断其哈希值,然后经过特定运算取余,得到在数组中的索引,如果索引位置尚未有元素存储,则直接存储,若有元素,然后通过equals方法进行比较,若Key值相同,则保留原有的值,若Key值不同,则就此链表继续向下进行比较,直到最后一个元素也不相同,然后将此元素插入.
数组的扩容机制是扩大到原来的二倍
当一个位置上出现八个元素时,就会认为Hash函数设计不好,且数组长度大于64,就会自动转换为红黑树,提高性能
Hashtable扩容机制
底层有数组Hashtable$Entry[],初始化大小为11,当达到它的临界值也就是11*0.75就会进行扩容,按照当前容量的2倍+1进行扩容
ArrayList和LinkedList的区别
ArrayList | LinkedList | |
---|---|---|
存储 | 底层以数组来实现 | 基于双向链表存储 |
占用内存大小 | 占内存大 | 占内存小 |
访问效率 | 快 | 慢 |
理论上在非首位上插入和删除 | 慢 | 快 |
总体上来说想要查询元素就使用ArrayList想要删除,插入快就选择LinkedList