JAVA集框架# JAVA集合
分为四个部分:
- 集合框架体系
- Collection
- Map
- Collections
一、集合框架体系
java集合类非常多,主要分为两类,Collection和Map。
先来看Collection接口:它继承了Iterable接口,并分出了list和set接口,而Iterable有迭代器的作用,可以用来遍历Collection
单列集合:单个单个的元素
list:ArrayList、LinkedList、Vector;
set:HashSet、TreeSet
接下来是Map:
双列集合:键值对存放
Map:HashTable、HashMap、TreeMap
二、Collection
Collection方法(todo)
1.Interator接口的方法
可以用来遍历Collection的实现类
hasNext():可以用来判断是否还有下一个元素,返回true和false
next():下移一次指针,返回元素
- 提示:在调用Interator.next()之前,一定要先进行Interator.hasNext()判断,否则会抛出异常。
这是一个Arrays.sort方法的例子:
需要记住的是,这个方法只能对数组使用,不能对ArraysList等使用,因为他们是一个对象。
Book[] books=new Book[3];
books[0]=new Book(20.1,"金瓶梅");
books[1]=new Book(100.2,"红楼们");
books[2]=new Book(90.2,"唐诗三百首");
Arrays.sort(books, new Comparator<Book>() {
@Override
public int compare(Book o1, Book o2) {
Book book1=(Book)o1;
Book book2=(Book)o2;
double val=book1.price-book2.price;
if(val>0){
return 1; }else if(val<0){
return -1; }else{
return 0; }
}});
System.out.println(Arrays.toString(books));
接下来才是Iterator使用案例:
Collection books=new ArrayList();
books.add(new Book(90.2,"hongloum"));
books.add(new Book(100.2,"javabinan"));
books.add(new Book(200.2,"computer"));
Iterator iterator=books.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
2、用增强版for遍历Collection
for (Obiect obj: books){
sout(obj);
}
本质上就是底层简化的Iterator迭代器。
3、List接口和常用方法
list集合存放有序元素,并且每一个元素都有自己对应的索引值,元素可重复。
①常用方法:
- void add(int index,Object object);
向集合中的指定index位置插入object。其中一个重载函数void add(Object object),可以直接插入元素。 - boolean addAll(int index,Collection col);
把col中的元素一个一个全部插入index位置以及后面。 - int get(int index)
返回索引值 - int indexof(Object obj);
返回第一次出现这个元素的索引 - int lastindexof(Object obj)
返回最后一个元素索引 - Object remove(int index);
删除索引为index的元素,并且返回此元素 - Object set(int index,Object object)
设置新元素
②List的三种遍历
- 利用迭代器Interator遍历,前面有示例代码
- for-each
- 普通for
4、ArraysList
注意事项:
- 可以放所有元素,甚至放空元素
- 基于数组实现的数据存储
- 和Vector差不多,但是ArraysL是线程不安全的,在多线程时,不建议使用它,但是使用效率却高。
①扩容机制
- ArraysList里面中维护了一个Object类型elementData里面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HwtJKvlg-1624975374310)(en-resource://database/926:1)] - 当使用无参构造时,默认容量为0,第一次添加时会扩容为10,往后每次扩容为1.5
- 如果使用指定大小的构造器,则每次扩容直接变为1.5倍。new ArraysList(int)
扩容机制源码分析:先写一个测试程序,然后debug看其扩容机制
ArraysList list=new ArrayList();
for(int i=0;i<10;i++)
{
list.add(i);
}
for(int i=0;i<100;i++)
{
list.add(i);
}
调用无参构造源码解析在下图
扩容机制完成之后,就不断回调。回到最初的add函数,添加完毕之后,扩容添加的操作也就完成了。可以看出,这一番操作下来,每一次添加之前,都需要进行扩容判断,所以会造成一定的负担。
需要掌握的不是这个源码,而是如何利用debug观看和学习源码。这里调用有参构造的源码不再赘述。
5、Vector
Vector的基本介绍:
- 底层也是Object[] elementDate数组;
- 是线程安全的,方法有synchronized约束同步;
- 在开发时,如果需要保证线程同步,可以使用Vector;
①扩容机制
ArraysList | Vector |
---|---|
底层是数组 | 底层是数组 |
线程不安全但是效率高 | 线程安全但是效率低 |
i.无参构造时,容量为10,往后1.5倍扩容;ii.有参构造时,往后直接1.5倍扩容 | i.无参构造时,容量为10,往后2倍扩容;ii.有参构造时,往后直接2倍扩容 |
②底层源码
还是一样的先写一段测试代码:
Vector vector=new Vector();//打上断点
for(int i=0;i<10;i++)
{
vector.add(i);
}
debug之后可以发现,不管是有参还是五参数,都会进入一个有参构造函数中,默认值为10。然后进行和ArraysList相同的add操作,先判断是否装满了,如果没有装满,则扩容,然后再添加。
6、LinkedList
LinkedList的基本介绍:
- 底层实现了双端链表和双端队列;
- 可以添加任意元素,甚至null;
- 同样是线程不安全的;
①底层构造
LinkedList对象里主要维护了三个属性:
- size:长度
- first:第一个节点
- last:第二个节点
每个节点中又维护了三个属性:
- item:此节点存放的数据对象
- next:下一个节点
- prev:上一个节点
②双向链表的增删改查
略
到这里,Collection中的List部分也就基本介绍完了,接下来是另一个继承了Collection接口的Set接口部分。
7、Set接口及其常用方法
set的基本介绍:
- 继承了Collection接口
- 里面存放的元素是无序的,每一个元素只能存放一次,如果存入相同元素,则会直接忽略,可以存入null,但是只能存放一次
- 输出无序,但是却是一定的,不会因为两次编译和运行而改变。
①Set的遍历
和List的遍历稍有区别。因为Set是没有所以的,所以不能用一般的for循环来遍历。因为Set继承了interable接口,所以可以使用迭代器来进行遍历:
i.interator
ii.for(Object obj: set)
8、HashSet
HashSet的基本介绍:
是Set接口的一个实现类,底层是HashMap,其他属性继承了Set接口。
①不可重复元素再理解
不重复元素,实际上指的是不同的对象。来看下面的例子
Set set=new HashSet();
//1
sout(set.add("wenshuai"));//T
sout(set add("wenshuai"));//F
//2
sout(set.add(new Dog("wang")));//T
sout(set.add(new Dog("wang")));//T
//3
sout(set.add(new String("haixia")));//T
sout(set.add(new String("haixia")));//F
为什么会产生上述结果?
1.对于直接申请的String字符串,首先会在常量池中寻找,有则直接引用,没有则想常量池中添加再引用。因此第二个String创建时,常量池中已经存在wenshuai,所以二者创建的是同一个对象。因此第二个不能添加。
2.通过new出来的一般都是两个不同的对象,只是这两个对象里面的属性相同而已。
3.按理来说,这两个不是同一个对象,但是第二个却无法添加。原因和HashSet底层源码有关,存疑(todo)。