一 、Collection 接口
1、List接口
不唯一,有序的序列
1.1ArrayList
集合的概念:集合就是对象的容器,存储对象的对象,可代替数组。位于java.util包
特点
- ArrayList实现类底层是一个Object数组
- Array List实现类有下标 ,元素可以重复
- Array List实现线程不安全
- ArrayList实现类增删效率低,因为会移动元素的位置。查询的效率高,因为有下标,访问方便。
构造方法的变化
- 在JDK 1.7版本之前,ArrayList的无参构造默认的创建一个容量为10的一个Object数组。
- 在JDK1.8版本的时候,做了改进,刚创建ArrayList的时候,只给他一个变量名,避免过多的浪费内存空间。当进行添加元素的时候,再给他一个容量为十的数组。
遍历方式
普通的for循环便历
利用ArrayList的size()方法获取有效元素个数
for-each循环便历
使用迭代器遍历
- 先获取迭代器 ArrayList.iterator()
- 利用迭代器的hasNext()方法作为while循环的判断
- 利用迭代器的Next()方法打印元素
List<Integer> number = new ArrayList<Integer>(); number.add(24 ); number.add(121 ); number.add(224 ); number.add(244 ); number.add(1224 ); number.add(214 ); //遍历的方法1: for(int i = 0 ; i < number.size() ; i++ ) { System.out.println(number.get(i)); } System.out.println("=============="); //遍历的方式2: for(Integer i : number) { System.out.println(i); } System.out.println("=============="); //遍历的方式3: Iterator<Integer> iterator = number.iterator(); //获得一个迭代器 while(iterator.hasNext()) { //hasNext()判断的是集合是否有下一个元素,有就是true System.out.println(iterator.next()); //next()方法返回迭代器的下一个元素 }
ArrayList 常用的方法 最好参考API
- add
- add(Object obj)
- add(int index ,Object obj)
- size()
- get(int index)
- contains(Object obj) 查找集合中obj是否存在
- remove
- remove(int index)
- remove(Object obj)
- Collection中常被用的方法
- isEmpty() 集合是否为空
- iterator() 返回一个迭代器
- clear() 清空
- toArray() 返回一个数组
1.2Vector
- 1.0版本就出现了,线程安全。在1.2版本中,添加了ArrayList,方法和Vector 相似,线程不安全。
- 底层也是数组,扩容为2倍
- Vector与Array List的区别
- vector线程安全,ArrayList线程不安全
- vector扩容两倍,ArrayList扩容1.5倍
- 初始化容量都是10,但是ArrayList刚创建 的时候,初始容量为0,只有添加元素的时候,才会初始化容量10。vector创建时就是10.
1.3LinkedList
介绍:
双向链表结构,线程不安全,
特点
- 增删快(因为空间不连续,链表中的元素都是分为三部分组成的:值、上一个元素的引用,下一个元的引用(即地址)。因此,当增删的时候,只需要改变元素中的索引就能完成)。查询慢。
- LinkedList因为元素中的组成比较多,因此他比ArrayList占用更多的空间
- 但是也因为LinkedList空间不连续,所以可以更好的利用内存中的碎片空间。
循环:也可以有三种循环方式
- 普通的for循环便历 (但是,LinkedList没有下标,因此不推荐使用,因为他太慢了)
- for-each循环便历
- 使用迭代器遍历
List<Integer> list = new LinkedList<Integer>(); for(int i = 0 ; i < 100000 ; i++) { list.add(i); } //为了统计一下所用的时间,定义的一个开始参数 long start = System.currentTimeMillis() ; //使用迭代器 Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()) { System.out.println(iterator.next()); } //使用for-each // for(Integer i : list) { // System.out.println(i); // } //使用for循环,效率太低 // for(int i = 0 ; i < list.size() ; i++) { // System.out.println(list.get(i)); // } //为了统计一下所用的时间,定义的一个结束参数 long end = System.currentTimeMillis() ; System.out.println(end - start);
1.4 ArrayList与LinkendList的比较
- ArrayList 集合底层是一个数组
- LinkedList底层是上链表结构实现的
2、Set接口
唯一,无序,
2.1HashSet
特点:
- 无序,无下标 ,元素不容许重复
- 底层是HashMap集合
- 线程不安全
- 元素不能重复,原理是通过调用元素本身的equals做了比较
方法:继承Collection 因此方法和Array List相似
循环的方法:Set接口没有get方法、
第一种:for-each循环
第二种:迭代器
Set<String> set = new HashSet<String>(); set.add("1"); set.add("1"); set.add("31"); //第一种:for-each循环 for(String s : set){ System.out.println(s); } System.out.println("======"); //第二种:迭代器 Iterator<String> it = set.iterator(); while(it.hasNext()){ System.out.println(it.next()); }
二、Map接口
键值对的形式
1、HashMap
- HashMap的数据结构
- JDK7之前的是数组+单项链表的形式
- JDk8之后采用的是数组+链表的结构,当链表的元素个数超过8个的时候,链表结构会被扩展为变成红黑树的结构模式。
- 1.2版本开始,无参构造方法,会创建一个初始容量为16(可以自定义,但是最好是2的倍数)的Node<k,y>类型的数组,他的默认负载系数是0.75。
- 负载系数就是,当使用超过0.75的时候,就会进行两倍的扩容。
特点:
- 键值对的存储形式
- 无下标,无序
- 键和值允许为空,但是键不可以重复,值可以重复
- 线程不安全
扩容为2倍
常用的方法:
- put(K key, V value) 添加元素
- remove(Object key) 移除元素,返回移除的值
- clear() 清空
- contains 返回Boolean
- containsKey(Object key) 集合是否含有这个键
- containsValue(Object value) 集合是否含有这个值
- set 返回Set集合
- entrySet() 返回所有的set视图(键和值),
- keySet() 返回所有的key视图
- values() 返回一个collection集合,含有所有的值
- get(Object key) 根据键返回值
- isEmpty() 判断是否为空
- size() 返回键值对的数量
遍历的方式:Map集合和Set集合都是无序的,没有get(Object key)方法,不能用for循环,只能用for-each
第一种 :这种方式的效率比较低
- 利用keySet() 方法返回key的set集合
- 再循环用key值返回value
第二种 :
- 利用values () 方法返回value的collection集合
- 再循环遍历collection集合,就能得到所有的value值
第三种:
- 利用entrySet得到一个Set<Entry<k,v>>集合
- 再利用循环打印entry.getKey() 以及 entry.getValue()
第四种
- 利用entrySet().iterator() 获得迭代器
- 然后迭代器中的每一个元素都是Entry类型的元素,所以可以使用entry.getKey() 以及 entry.getValue()
//第一种;凡是根据key值查找的效率都比较低 Set<Integer> keySet = map.keySet(); for(Integer i : keySet) { System.out.println("key:" +i); System.out.println("值为:" + map.get(i)); } //第二种 System.out.println("========="); Collection<String> values = map.values(); for(String s : values) { System.out.println("值为:" + s); } //第三种 Set<Entry<Integer, String>> entrySet = map.entrySet(); for(Entry<Integer , String> e : entrySet) { System.out.println(e.getKey() + "+ " + e.getValue()); } //第四种 Iterator<Entry<Integer, String>> it = map.entrySet().iterator(); while(it.hasNext()) { Entry<Integer, String> e = it.next() ; //注意:不能在一个循环中直接用it.next()分别调用getKey()和getValue(),不然key和value值不匹配 //错误的示范:System.out.println(it.next().getKey() + "=" + it.next().getValue()); System.out.println(e.getKey() + "=" + e.getValue()); }
注:entry是一个接口
Map.entrySet方法返回地图的集合视图,其元素属于此类。 获取对映射条目的引用的唯一方法是从该集合视图的迭代器。 这些Map.Entry对象仅在迭代期间有效; 更正式地,如果在迭代器返回条目之后已经修改了背景映射,则映射条目的行为是未定义的,除非通过映射条目上的setValue操作。
常用的方法:
boolea equals(Object o)将指定的对象与此条目进行比较以获得相等性。 K getKey()返回与此条目相对应的键。 V getValue()返回与此条目相对应的值。 int hashCode()返回此映射条目的哈希码值。 V setValue(V value)用指定的值替换与该条目相对应的值(可选操作)。
2、Hashtable
- 特点:
- 键值都不支持null
- 初始容量为11
- 线程安全 ,效率低。 1.0版本出现的Hashtable
- 扩容的时候,扩大两倍+1
- 常用的方法:常用的方法和HashMap方法相似,如果不为了保证线程的安全,推荐使用HashMap
- 遍历的方式与HashMap的遍历方式一样
3、HashMap与Hashtable的区别
- Hashmap是个线程不安全的类,Hashtable是一个线程安全的类
- HashMap初始容量为16,Hashtable初始容量为11
- 扩容时,前者扩大两倍,后者扩大两倍加1
- 前者可以将null作为键值对的值,后者则不中
三、泛型
泛型集合【重点-解决应用问题】:
- 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
- 特点:
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型之间引用不能相互赋值,泛型不存在多态。
泛型:常用名称:E = Element / T = Type / K = Key / V = Value
- 概念:约束-规范类型
- 泛型的应用场景
- 实例泛型:
- 类名后面:创建对象时,为类定义的泛型,进行参数化赋值
- 接口名的后面:实现接口时,为接口所定义的泛型,进行参数化赋值
- 静态泛型:
- 方法的返回值类型的前面
- 定义在方法的形参列表之中,不支持使用& 只能应用在形参列表上,规范泛型。
//1、定义在类之中的泛型: public class Test { public static void main(String[] args) { //创建对象时,给泛型什么类型,那么在类中的实例方法中的引用就会是什么类型,能规范,统一类型 Student<String> stu1 = new Student<String>(); stu1.ma("afa"); Student<Integer> stu = new Student<Integer>(); stu.ma(45); } } class Student<T> { public void ma(T t) { t.toString() ; } } //2、定义在接口之中的泛型 interface Run<T>{ //4、返回值的泛型 public T ma(); } //在接口实现的时候,需要给一个具体类型,那么这个实现类实现的方法中关于这个泛型,都会变成这个具体的类型 public class Test1 implements Run<String>{ public String ma() { return "aafga"; } } //3、定义在方法形参列表之中 <? extends Person>代表了父类Person以及他的所有子类。 public class Test { public static void ma(Set<?> set) { Iterator<?> it = set.iterator(); while(it.hasNext()) { System.out.println(it.next()); } } public static void main(String[] args) { Set<String> set1 = new HashSet<String>(); set1.add("a");set1.add("r");set1.add("qa"); ma(set1); Set<Integer> set2 = new HashSet<Integer>(); set2.add(1);set2.add(2);set2.add(3); ma(set1); } }
四、Collections工具类:
概念:集合工具类,定义了除了存取以外的集合常用方法。
- public static <T extends Comparable<? super T>> void sort(List list) //排序,要求:必须实现Comparable,必须可与自身类型比,以及父类类型比
- public static void reverse(List<?> list) //反转、倒置元素
- public static void shuffle(List<?> list) //随机重置顺序
- binarySearch(List<? extends Comparable<? super T>> list, T key) 查找
- max( ) min()
Comparable<? super T>
该接口对实现它的每个类的对象强加一个整体排序。 这个排序被称为类的自然排序 ,类的compareTo方法被称为其自然比较方法 。
- comparableTo(T o)方法中定义了用sort()方法进行比较的方式
- 他的规则就是当前的对象如果比o大,则返回1;
- 当前的对象如果比o小,则返回-1;
- 当前的对象如果与o相等,则返回0;
只有实现了这个接口的类(重写compareTo方法)才能使用Collections.sort(List list)
public class Test { public static void main(String[] args) { List<Student> list = new ArrayList<Student>(); Student stu1 = new Student("afhhg" , 34); Student stu2 = new Student("af" , 14); Student stu3 = new Student("hg" , 24); Student stu5 = new Student("afg" , 4); list.add(stu1);list.add(stu2);list.add(stu3);list.add(stu5); //排序 Collections.sort(list); for(Student s : list) { System.out.println(s); } //倒置 System.out.println("======"); Collections.reverse(list); for(Student s : list) { System.out.println(s); } //随机重置顺序 System.out.println("======"); Collections.shuffle(list); for(Student s : list) { System.out.println(s); } } } class Student implements Comparable<Student>{ private String name ; private int age ; public int compareTo(Student o) { if(this.getAge() > o.getAge()) { return 1; }else if(this.getAge() == o.getAge()) { return 0; }else { return -1 ; } } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } public int getAge() { return age; } public Student(String name , int age) { this.name = name ; this.age = age ; } }