Java集合框架解析

来源:互联网 发布:精点数据 编辑:程序博客网 时间:2024/06/05 14:30
数组即可以储存基本数据类型,也可以存储引用类型。
集合和数组的区别
A:长度区别
数组固定
集合可变
B:内容区别
数组可以是基本类型,也可以是引用类型
集合只能是引用类型
C:元素内容
数组只能存储同一种类型
集合可以存储不同类型(其实集合一般存储的也是同一种类型)
Collection体系
|--List
|--ArrayList
|--Vector
|--LinkedList
|--Set
|--HashSet
|--TreeSet
Collection的功能
A:添加功能
boolean add(Object e)添加元素,不允许有重复添加,如果包含重复元素, 返回false
B:删除功能
ovid clead()移除所有元素
boolean remove(Object o)移除元素,如果包含指定的元素, 返回true
boolean removeAll(Collection<?> c)移除此collection中包含指定的collection中的所有元素
boolean retainAll(Collection<?> c)保留此collection中那些也包含collection的元素
C:判断功能
boolean equals(Object o)比较collection与指定对象是否相等
boolean isEmpty()如果此 collection 不包含元素,则返回 true。
boolean containsAll(Collection<?> c)包含指定的connection指定的元素则返回true
D:获取功能
Object[] toArray()返回包含此 collection 中所有元素的数组。
E:长度功能
int size()返回此collection中的长度
Collection集合的遍历:
迭代器:Iterator<Object> iterator()返回此collection的元素上进行迭代的迭代器
A:是集合的获取元素的方式。
B:是依赖于集合而存在的。
迭代器原理:  
迭代器是对集合进行遍历,而每一个集合内部的存储结构都是不同的,
所以每一个集合存和取都是不一样,那么就需要在每一个类中定hasNext()和next()方法,
这样做是可以的,但是会让整个集合体系过于臃肿,迭代器是将这样的方法向上抽取出接口,
然后在每个类的内部,定义自己迭代方式,这样做的好处有二,第一规定了整个集合体系的遍历方式都是hasNext()和next()方法,第二,代码有底层内部实现,使用者不用管怎么实现的,会用即可
集合(List)
List是Collection的子接口
特点:有序(存储顺序和取出顺序一致),可重复。
迭代器功能:
size()和get()方法迭代
Iterator<Object> iterator()返回按适当顺序在列表的元素上进行迭代的元素(没有特有功能,进行元素修改会发生并发异常)
ListIterator<Object> listIterator()返回此列表元素的列表迭代器(该子接口实现了父类所有方法,并有自己特有的增加和迭代方法"向后迭代")
修改功能:
Object set(int index,Object element)用指定的元素替换列表中指定位置的元素
并发修改异常:
A:出现的现象
迭代器遍历集合,集合修改集合元素
B:原因
迭代器是依赖于集合的,而集合的改变迭代器并不知道。
C:解决方案
a:迭代器遍历,迭代器修改(ListIterator)
元素添加在刚才迭代的位置
b:集合遍历,集合修改(size()和get())
元素添加在集合的末尾
常见数据结构:
A:栈 先进后出
B:队列 先进先出
C:数组 查询快,增删慢
D:链表 查询慢,增删快
List的子类特点:
ArrayList
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
Vector
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
LinkedList
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
泛型:
泛型是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。
格式:
<数据类型>
public <泛型类型> 返回类型 方法名(泛型类型 变量名)
该数据类型只能是引用类型。
好处:
A:把运行时期的问题提前到了编译期间
B:避免了强制类型转换
C:优化了程序设计
可变参数:
我们在写方法的时候,参数个数不明确,就应该定义可变参数。
格式:
修饰符 返回值类型 方法名(数据类型... 变量) {}
A:该变量其实是一个数组名
B:如果一个方法有多个参数,并且有可变参数,可变参数必须在最后


集合框架(HashSet如何保证元素唯一性的原理
HashSet原理:
使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个equals()比较, 
效率较低,哈希算法提高了去重复的效率, 降低了使用equals()方法的次数,
当HashSet调用add()方法存储对象的时候, 先调用对象的hashCode()方法得到一个哈希值, 
然后在集合中查找是否有哈希值相同的对象,如果没有哈希值相同的对象就直接存入集合,
如果有哈希值相同的对象, 就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存
hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)
equals(): 属性相同返回true, 属性不同返回false,返回false的时候存储
HashSet集合:
底层数据结构是哈希表(是一个元素为链表的数组)
哈希表底层依赖两个方法:hashCode()和equals()
由hashCode()和equals()保证数据唯一性
public boolean equals(Object obj) {
if (this == obj)//调用的对象和传入的对象是同一个对象
return true; //直接返回true
if (obj == null)//传入的对象为null
return false; //返回false
if (this.getClass() != obj.getClass())//调用的对象对应的字节码对象和传入对象对应的字节码对象不是同一个对象
return false; //返回false
Person other = (Person) obj;//向下转型,可以调用子类特有的属性和行为
if (age != other.age)//如果调用的对象的age不等于传入对象的age
return false; //返回false
if (name == null) {//如果调用的name为null
if (other.name != null)//而传入的对象name不为
return false; //返回false
} else if (!name.equals(other.name))//如果调用对象的name和传入对象的name不是同一个name
return false; //返回false
return true; //返回true
为什么hashCode保证唯一性的时候会采用质数31呢?
1,因为31是一个质数(只能被1和本身整除)
2,31这个数既不大,也不小(大了int不能接收)
3,31是2的5次方-1(2向左移动5次在减一)
equals是Object类提供的方法之一,众所周知,每一个java类都继承自Object类,
所以说每一个对象都有equals这个方法。而我们在用这个方法时却一般都重写这个方法
Object类中equals()方法的源代码
public boolean equals(Object obj) { 
return (this == obj); 
}
从这个方法中可以看出,只有当一个实例等于它本身的时候,equals()才会返回true值。
通俗地说,此时比较的是两个引用是否指向内存中的同一个对象,也可以称做是否实例相等。
而我们在使用equals()来比较两个指向值对象的引用的时候,
往往希望知道它们逻辑上是否相等,而不是它们是否指向同一个对象——这就是我们通常重写这个方法的原因。
String s1 = new String(“kvill”),String s2 = new String(“kvill”); 
s1.equals(s2)为ture,说明String类中已经重写了equals()方法,
如果不重写equals()方法,那么s1.equals(s2)默认比较两个对象所指向的内存地址是否相同,返回值必然为false。
重写equals()方法看起来非常简单,但是有许多改写的方式会导致错误,并且后果非常严重。
要想正确改写equals()方法,你必须要遵守它的通用约定。
下面是约定的内容,来自java.lang.Object的规范,equals方法实现了等价关系,
以下是要求遵循的5点,这5点都是当年数学的概念啊
1. 自反性:对于任意的引用值x,x.equals(x)一定为true。 
2. 对称性:对于任意的引用值x 和 y,当x.equals(y)返回true时,y.equals(x)也一定返回true。 
3. 传递性:对于任意的引用值x、y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也一定返回true。
4. 一致性:对于任意的引用值x 和 y,如果用于equals比较的对象信息没有被修改,多次调用x.equals(y)要么一致地返回true,要么一致地返回false。
5. 非空性:对于任意的非空引用值x,x.equals(null)一定返回false。
了解了equals重写,我们再看hashCode()这个方法,hashcode()这个方法也是从object类中继承过来的,在object类中定义如下
public native int hashCode();
说明是一个本地方法,它的实现是根据本地机器相关的。
再看它比较"官方"的详细说明:hashCode()返回该对象的哈希码值,该值通常是一个由该对象的内部地址转换而来的整数,它的实现主要是为了提高哈希表(例如java.util.Hashtable提供的哈希表)的性能。
你可以对它的这样"官方式"的定义漠视,但以下这一点你必须铭记:
在每个重写了equals方法的类中,你必须也要重写hashCode方法。
如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法与所有基于散列值(hash)的集合类结合在一起正常运行。
hashCode()的返回值和equals()的关系如下:
如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。 
如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。


TreeSet集合:
底层数据结构是红黑树(是一个自平衡的二叉树)
保证元素的排序方式
自然排序(元素具备比较性)
让元素所属的类实现Comparable接口
比较器排序(集合具备比较性)
让集合构造方法接收Comparator的实现类对象
Collection集合总结:
Collection
|--List 有序,可重复
|--ArrayList
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高
|--Vector
底层数据结构是数组,查询快,增删慢。
线程安全,效率低
|--LinkedList
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高
|--Set 无序,唯一
|--HashSet
底层数据结构是哈希表。
如何保证元素唯一性的呢?
依赖两个方法:hashCode()和equals()
开发中自动生成这两个方法即可
|--LinkedHashSet
底层数据结构是链表和哈希表
由链表保证元素有序
由哈希表保证元素唯一
|--TreeSet
底层数据结构是红黑树。
如何保证元素排序的呢?
自然排序
比较器排序
如何保证元素唯一性的呢?
根据比较的返回值是否是0来决定
集合中常见的数据结构(掌握)
ArrayXxx:底层数据结构是数组,查询快,增删慢
LinkedXxx:底层数据结构是链表,查询慢,增删快
HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()和equals()
TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序














0 0
原创粉丝点击