集合和数组都是存储元素用的,二者的区别为:
1.集合
集合是一个容器,它可用来存取对象
集合比数组强大,在一些特定情况下,使用数组不方便,这时就可以使用集合来做
特点:
1.集合长度是可变的
2.可以存储任意类型的object
3.有序也无序
2.数组
数组也是一个容器,可以用来装同一类型的数据
特点:
1.数组定长
2.数据类型相同
3.有下标,可以按顺序遍历
﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋
Collection 体系
集合顶层接口,表示一组对象,有元素唯一和不唯一性,
常用方法有:
1.增加
boolean add(E e) 增加一个对象
boolean addAll(Collection<? extends E> c) 增加一个集合的对象
2.删除
void clear() 移除此Collection中所有的元素
boolean remove(Object o) 删除一个指定的元素
boolean removeAll(Collection<?> c) 删除两个集合中共有的元素(删除交集?)
boolean retainAll(Collection<?> c) 保留两个集合中共有的元素(保留交集)
3.修改
4.查找
boolean contains(Object o) 当前集合中是否包含一个元素
boolean containsAll(Collection<?> c) 判断两个集合中的元素是否完全相同(忽略顺序)
boolean isEmpty() 如果此 collection 不包含元素,则返回 true。
5.迭代器
对集合中的元素进行遍历。
Iterator<E> iterator() 返回该集合的迭代器
使用迭代器的三个步骤:
1.获取迭代器Iterator<E> it = 集合对象.iterator()
2.通过迭代器判断是否有下一个元素。 it.hasNext()
3.获取集合中的元素it.next()
void remove() 方法和Collection中 boolean remove(Object o) 方法的区别;
最大的区别在于:
在迭代过程中,不能用集合对象对集合进行 remove操作。否则抛出异常。
java.util.ConcurrentModificationException当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
在使用迭代器中的 remove方法时需要注意
while(it.hasNext()){
it.next(); //要先获取当前元素,再进行操作,否则运行出异常
it.remove();
}
﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋
集合中包含两大类
1.List有序可重复(有序:指存储和取出顺序一致。重复:指满足e1.equals(e2)的元素可重复 )
List中特有方法:
1.查找
E get(int index) 返回列表中指定位置的元素。
int indexOf(Object o) 返回指定元素在列表中第一次出现的索引
int lastIndexOf(Object o) 返回指定元素在列表中最后一次出现的索引
List<E> subList(int fromIndex, int toIndex) 返回指定索引范围内的元素
2.删除
E remove(int index) 根据指定索引删除指定元素并返回该元素
3.修改
E set(int index, E element) 用指定元素替换掉指定索引上的元素,并返回被替换掉的元素
4.迭代器
ListIterator<E> listIterator()返回该列表的迭代器
ListIterator<E> listIterator(int index) 返回该列表的迭代器,从指定索引开始
ListIterator 列表迭代器。
允许双向遍历列表,迭代器期间可对列表进行操作:增加、删除、替换
注意:倒置遍历的时候,需要正序迭代遍历一次。
List可遍历的方法有三种:
1.父类接口的iterator
2.ListIterator
3.for循环,get(int index) //因为有索引,就可以利用循环操作
1.1.ArrayList *****
底层数据结构是数组,线程不安全[效率高],每次增加元素容量增加 50%查询快、增删慢
1.2.Vector
底层数据结构是数组,线程安全[效率低],每次增加元素容量增加 100%查询快、增删慢
特殊方法(被JDK1.2替代之前的方法)(JDK升级条列中有一条就是:简化书写):
1.增加: void addElement(E obj) --> boolean add(E e)
2.删除: E elementAt(int index) --> E get(int index)
3.迭代器: Enumeration<E> elements() --> iterator(该方法是继承父类的并且没有重写,所以在本类APi中查不到)
1.3.LinkedList
底层数据结构是链表,线程不安全[效率高],查询慢、增删快[提供了头尾元素的操作]
特殊方法:
1.增加
void add(int index, E element) 在指定索引处增加元素
boolean addAll(int index, Collection<? extends E> c) 将指定 collection 中的所有元素从指定位置开始插入此列表。
void addFirst(E e) 将指定元素插入此列表的开头
void addLast(E e) 将指定元素添加到此列表的结尾。
2.删除
E removeFirst() 移除并返回此列表的第一个元素。
E removeLast() 移除并返回此列表的最后一个元素。
3.查找
E getFirst() 返回此列表的第一个元素。
E getLast() 返回此列表的最后一个元素。
4.迭代器
ListIterator<E> listIterator(int index) 返回以逆向顺序在此双端队列的元素上进行迭代的迭代器。
元素将按从最后一个(尾部)到第一个(头部)的顺序返回。
Iterator<E> descendingIterator()
以后到底使用谁?根据特点判断
线程是否安全?
是:Vector(后期有改进的类替换)
否:用Arraylis 或 LinkedList
是查询多:ArrayList(查询:指遍历,获取等)
是增删多:LinkedList(增:指插入。而头尾操作性能高)
2.Set无序唯一(唯一:不包含满足 e1.equals(e2) 的元素)
1.HashSet
底层数据结构是哈希表,线程不安全[效率高]
1.HashSet 是如何保证元素的唯一?看源码发现:
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
比较哈希值 &&。。。 || 比较equals
所以HashSet保证元素的唯一性他依赖与两个方法:hashCode 和 equals
重写hashCode:(一般是不需要手动写的)
return this.name.hashCode + this.age * 11(通常写一个素数)
为什么要 * 一个素数?
假设 20 + 30 = 5040 + 10 = 50 ,所以这个样子 返回的哈希值也是相同的,但是对象属性是不同的。就违背了改进的原则
让哈希值尽可能的不同,又要尽可能的相同,去比较equals。(看不懂的去看 word笔记)
2.迭代器父类的普通迭代器
2.TreeSet首先无序唯一,但是存储的数据按照自然排序存储。
底层数据结构是二叉树,线程不安全[效率高]元素唯一[性能底,二叉树判断重复、自然排序性能低]
1是如何保证元素的唯一的呢?
有两种实现方式:
1.方式一:让元素本身具备比较性,让自定义类实现Comparable接口
根据返回值进行比较排序
0 :相同
1 :比以前的元素大,放在右边
-1:比以前的元素小,放到左边
返回条件,根据自己的需求比较,返回以上的值
2.方式二:让集合具备比较性。通过构造传递一个Comparator接口的子类对象(暴力强制破坏元素自身的自然比较)
一般可以使用匿名内部类来创建该子类,重写方法的返回值的原理和方式一一样
注意:在开发中,因为TreeSet效率太低,一般使用HashSet
将集合变成数组:
<T> T[] toArray(T[] a)将集合变成数组
a: 存储此 collection 元素的数组(如果其足够大);否则,将为此分配一个具有相同运行时类型的新数组。
Arrays类public static <T> List<T> asList(T... a)将数组变成集合
返回一个受指定数组支持的固定大小的列表。(对返回列表的更改会“直接写”到数组。)
﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋﹋
泛型:Jdk1.5后的新特性
把类型明确的动作放到了创建实例或则调用方法的时候进行【约束我们的类型】
注意:虽然集合可以存储不同类型的对象数据,但是大部分的时候,存储的都是同一种类型数据
使用泛型的好处:
1.将运行期间的问题提前到编译期间解决
2.泛型类优化了程序设计
3.避免了强制类型转换
4.提高了程序的安全性
泛型通配符 ? :
? extends E : 上限:E ?为E的子类即可
? super E: 下限:E ?为E的父类即可
泛型的使用:泛型可以在类上使用,也可以在接口上使用。
1.自定义泛型类:
泛型位置:在类名后面加上typeOf <T> //T为变量,一般t表示为数据类型
在类上声明的泛型可以在类的【实例】成员上使用.
类的成员:
1.成员属性:实例属性(非static)类属性(static)
2.成员方法:实例方法类方法
为什么只能在类的实列成员上使用:
因为静态成员随着类的加载而加载,不需要对象就可以使用,这时泛型就没有初始化。
2.自定义泛型方法:
泛型位置:声明在修饰符与方法返回类型之间。
泛型方法的作用:
不想使用类上声明的泛型,想要在参数和返回值之间建立起关联,就可以在方法上声明泛型
类泛型不能用在static方法上,但是可以在方法上自定义泛型