集合Collection整理

集合

概念
面向对象语言对事物的体现都是以对象的形式描述。为了方便对多个对象的操作,就要对对象进行存储(就像数组)。
但是数组存储对象有一些缺点,例如:长度不可修改,提供的方法非常有限,对于数据的增删改查不方便,对于无序,不可重复等数据不能满足。
味了更方便地对对象数据进行操作,就有了Java集合框架这一产物在这里插入图片描述

从上图可以看出,集合主要包括两种类型容器,一种是集合Collection(存储单个对象),一种是Map(存储键值对数据)。Collection接口又有三种子类型,List,Set,Queue。本篇博客将用来整理Collection集合的知识点。

集合框架都包含如下内容:

  • 接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象
  • 实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap
  • 算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
    如下图所示:在这里插入图片描述

迭代器(Iterator)

迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。

Collection集合元素的通用获取方式:在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。

集合中把这种取元素的方式描述在Iterator接口中。

Java中的Iterator功能比较简单,并且只能单向移动:

(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。(指针,指向第一个元素之前)

(2) 使用next()获得序列中的下一个元素。

(3) 使用hasNext()检查序列中是否还有元素。

(4) 使用remove()将迭代器新返回的元素删除。
使用方法


for(Iterator it = c.iterator(); it.hasNext(); ) {  
  Object o = it.next();  
   //要做的操作  
}

List

List接口 (有序、可重复 —> List也可以称为“动态数组”,用来替换数组)
常用方法:增:add(Object obj)
删: remove(int index) / remove(Object obj)
改: set(int index,Object ele)
查: get(int index)
插: add(int index,Object ele)
长度:size()

ArrayList

实现的是List接口
创建对象:与其他普通的引用数据类型创建方式完全相同,但要指定容器中存储的数据类型:

ArrayList<要存储元素的数据类型> 变量名 = new ArrayList<要存储元素的数据类型>();
“<要存储元素的数据类型>”中的数据类型必须是引用数据类型,不能是基本数据类型;
下面给出8种基本数据类型所对应的引用数据类型表示形式:

基本数据类型 对应的引用数据类型表示形式
byte Byte
short Short
Int Integer
long Long
float Float
double Double
char Character
boolean Boolean

常用方法
方法声明 功能描述
boolean add(Object obj) 将指定元素obj追加到集合的末尾
Object get(int index) 返回集合中指定位置上的元素
int size() 返回集合中的元素个数
boolean add(int index, Object obj) 将指定元素obj插入到集合中指定的位置
Object remove(int index) 从集合中删除指定index处的元素,返回该元素
void clear() 清空集合中所有元素
Object set(int index, Object obj) 用指定元素obj替代集合中指定位置上的元素

JDK7:
	ArrayList arr = new ArrayList(); 
			//底层创建了长度是10的Object[]数组 elementData
	arr.add(123);//如果此次的添加导致底层elementdata数组容量不够,则扩容
			默认情况下,扩容为原来的1.5倍,同时需要将原有数组中的数据
			复制到新的数组中
	结论:建议开发中使用带参数的构造器

JDK8:
	ArrayList arr = new ArrayList(); 
			//底层Object[]数组 elementData初始化为{} 并没有创建长度为10的数组
	arr.add(123);
			//第一次调用add()时,底层才创建了长度为10的数组
	扩容时和JDK7一样
小结:JDK8里改的节省了内存

LinkedList

LinkedList类是双向列表,列表中的每个节点都包含了对前一个和后一个元素的引用.
优点:增删效率较高
双向连标的形式

LinkedList list = new LinkedList(); 
内部声明了Node类型的first和last属性,默认值为null
list.add(123);//将123封装到Node中,创建了Node对象
private static class Node<E>{
	E item;
	Node<E> next ;
	Node<E> prev;
	Node(Node<E> next , element,Node<E> prev){
		this.next = next ;
		this.item = element;
		this.prev = prev ; 
	}
}
双向连标的形式

Vector

JDK7、JDK8中通过Vector()构造器创建对象时,底层都创建了长度为10的数组
扩容时,默认扩容为原来的数组长度的2倍

ArrayList、LinkedList、Vector异同点
相同点:都实现了List接口,存储的数据都是有序,可重复的。
不同点:
ArrayList:
作为List接口的主要实现类;执行效率高 线程不安全的
底层使用Object[]存储
LinkedList:
对于频繁的插入、删除操作,使用LinkedList效率会比ArrayList高
其它时候一般都使用ArrayList
底层使用双向链表存储
Vector:
作为List接口的古老实现类 执行效率低 线程安全的
底层使用Object[]存储

Set

Set接口 (无序、不可重复 —> 类似于高中讲的“集合” 无序、确定、互异)
三个主要实现类:

HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值
LinkedHashSet:作为HashSet的子类,遍历其内部数据时,可以按照添加的顺序遍历;
看似是有序的
TreeSet:使用红黑树存储:!!里面的元素必须是同一个类new出来的
可以按照添加对象的指定属性,进行排序

Set
Set:注重独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素
用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。

对象的相等性

引用到堆上同一个对象的两个引用是相等的。如果对两个引用调用hashCode方法,会得到相同的结果,如果对象所属的类没有覆盖Object的hashCode方法的话,hashCode会返回每个对象特有的序号(java是依据对象的内存地址计算出的此序号),所以两个不同的对象的hashCode值是不可能相等的。

如果想要让两个不同的Person对象视为相等的,就必须覆盖Object继下来的hashCode方法和equals方法,因为Object hashCode方法返回的是该对象的内存地址,所以必须重写hashCode方法,才能保证两个不同的对象具有相同的hashCode,同时也需要两个不同对象比较equals方法会返回true

该集合中没有特有的方法,直接继承自Collection。

HashSet
HashSet不存入重复元素的规则.使用hashcode和equals

由于Set集合是不能存入重复元素的集合。那么HashSet也是具备这一特性的。HashSet如何检查重复?HashSet会通过元素的hashcode()和equals方法进行判断元素师否重复。

当你试图把对象加入HashSet时,HashSet会使用对象的hashCode来判断对象加入的位置。同时也会与其他已经加入的对象的hashCode进行比较,如果没有相等的hashCode,HashSet就会假设对象没有重复出现。

简单一句话,如果对象的hashCode值是不同的,那么HashSet会认为对象是不可能相等的。

因此我们自定义类的时候需要重写hashCode,来确保对象具有相同的hashCode值。

如果元素(对象)的hashCode值相同,是不是就无法存入HashSet中了? 当然不是,会继续使用equals 进行比较.如果 equals为true 那么HashSet认为新加入的对象重复了,所以加入失败。如果equals 为false那么HashSet 认为新加入的对象没有重复.新元素可以存入.

总结:

元素的哈希值是通过元素的hashcode方法 来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法 如果 equls结果为true ,HashSet就视为同一个元素。如果equals 为false就不是同一个元素。

哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。

HashSet到底是如何判断两个元素重复?
add()当存入一个新元素的时候,会将新元素的哈希值与现有元素的hash值比较,如果hashcode()相同的话,会再用equals()比较两个对象是否相等,如果相同,会认为这是重复的元素,不会存入HashSet,add()方法返回的是boolean类型。

TreeSet
之前存储无序的,不可重复的数据可以存储在HashSet,有序的 可重复的数据存储在Arraylist,如果需要存储有序的 不可重复的数据 可以用TreeSet存储。

TreeSet集合排序的两种方式:

一,让元素自身具备比较性。

也就是元素需要实现Comparable接口,覆盖compareTo 方法。

这种方式也作为元素的自然排序,也可称为默认排序。

年龄按照搜要条件,年龄相同再比姓名。

二,让容器自身具备比较性,自定义比较器。

需求:当元素自身不具备比较性,或者元素自身具备的比较性不是所需的。

那么这时只能让容器自身具备。

定义一个类实现Comparator 接口,覆盖compare方法。

并将该接口的子类对象作为参数传递给TreeSet集合的构造函数。

当Comparable比较方式,及Comparator比较方式同时存在,以Comparator

比较方式为主。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值