概念:当我们需要对数据进行保存时,数据的类型可能多种多样,于是就有了数据结构,在java中对数据结构的实现就是我们的集合
1.可以动态保存多个对象,使用方便
2.提供一些方便操作的方法,增加,删除,查找
集合体系概述:Java集合框架是由一些接口,抽象类和具体类组成的,都位于Java.util包中
在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类型 }
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对象时,若使用无参构造时,当添加第一个元素时,将自动扩容为10,如果不能满足时,则会在当前容量下扩容1.5倍;若使用无参构造时,开始给定一定的容量的话,在容量不能满足的情况下,就会在当前容量的基础上扩容1.5倍
LinkedList底层实现了双向链表和双端队列的特点,可以添加任意元素,可包括null,线程不安全没有实现同步
Vector底层也是对象数组,是线程同步的,也就是线程安全的,但效率不高因为带有synchronized,在开发过程中,考虑到线程安全时,考虑使用Vector
扩容机制:如果是无参构造时,默认为10,满后则按当前容量的2倍进行扩容;若果是有参构造,指定大小,每次直接按2倍进行扩容
Set中所存储的元素是不能重复的,最多包含一个null
Set中元素是无序的,取出和添加的顺序是不一致的,没有索引
Set接口中的一些方法:由于Set接口继承了Collection接口,所以常用方法和Collection接口中的一样
Set接口的遍历方式与Collection接口中的遍历也是一样的可以通过,增强for,迭代器,但是不能用索引来获取
HashSet实现了Set接口,实际上是HashMap
可以存放null值,但只有一个,元素无序,取决于hash后再决定索引
当使用无参构造器创建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接口与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是List接口的一个实现类,他是一个根据需求而动态增长的数组.在Java中数组的标准长度是在创建时就定义好的,一旦给定就无法更改,有时我们需要一些动态的数组来存储数据,此时就可以使用ArrayList,但他的线程不是安全的,它的存储是通过添加的顺序进行存放数据
ArrayList扩容是在调用add()方法时,调用ensureCapacityInternal()来扩容的,通过判断是否需要扩容,扩容的话调用扩容的关键方法是grow()方法,空间扩至原来的1.5倍
我们可以看出其实就是通过判断新的数组的size,然后将原来的数组复制到新的数组中去
HashMap是使用默认长度为16数组加链表的形式存储的,每个数组中存储着链表
使用put方法添加元素时,首先会调用HashCoede方法,判断其哈希值,然后经过特定运算取余,得到在数组中的索引,如果索引位置尚未有元素存储,则直接存储,若有元素,然后通过equals方法进行比较,若Key值相同,则保留原有的值,若Key值不同,则就此链表继续向下进行比较,直到最后一个元素也不相同,然后将此元素插入.
数组的扩容机制是扩大到原来的二倍
当一个位置上出现八个元素时,就会认为Hash函数设计不好,且数组长度大于64,就会自动转换为红黑树,提高性能
底层有数组Hashtable$Entry[],初始化大小为11,当达到它的临界值也就是11*0.75就会进行扩容,按照当前容量的2倍+1进行扩容
ArrayList | LinkedList | |
---|---|---|
存储 | 底层以数组来实现 | 基于双向链表存储 |
占用内存大小 | 占内存大 | 占内存小 |
访问效率 | 快 | 慢 |
理论上在非首位上插入和删除 | 慢 | 快 |
总体上来说想要查询元素就使用ArrayList想要删除,插入快就选择LinkedList