发表于: 2017-08-17 22:53:48
1 1065
今天完成的事情:
今天看了一下Java集合,总结了一些笔记。
1. 集合概述
1.1 什么是集合?
存储对象的容器,面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,存储对象,集合是存储对象最常用的一种方式。
集合的出现就是为了持有对象。集合中可以存储任意类型的对象, 而且长度可变。在程序中有可能无法预先知道需要多少个对象, 那么用数组来装对象的话, 长度不好定义, 而集合解决了这样的问题。
1.2 集合与数组的区别
数组和集合类都是容器
数组长度是固定的,集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象数组中存储数据类型是单一的,集合中可以存储任意类型的对象。
集合类的特点:
用于存储对象,长度是可变的,可以存储不同类型的对象。
数组的缺点:
存储类型单一的数据容器,操作复杂(数组一旦声明好不可变)CRUD。
1.3 集合的分类
集合做什么
1:将对象添加到集合
2:从集合中删除对象
3: 从集合中查找一个对象
4:从集合中修改一个对象就是增删改查
注意:集合和数组中存放的都是对象的引用而非对象本身
Java工程师对不同的容器进行了定义,虽然容器不同,但是还是有一些共性可以抽取最后抽取了一个顶层接口,那么就形成了一个集合框架。如何学习呢?当然是从顶层学起,顶层里边具有最共性,最基本的行为。具体的使用,就要选择具体的容器了。为什么? 因为不断向上抽取的东西有可能是不能创建对象的.抽象的可能性很大,并且子类对象的方法更多一些. 所以是看顶层,创建底层。那么集合的顶层是什么呢 叫做Collection
---|Collection: 单列集合
---|List: 有存储顺序, 可重复
---|ArrayList: 数组实现, 查找快, 增删慢
由于是数组实现, 在增和删的时候会牵扯到数组增容, 以及拷贝元素. 所以慢。数组 是可以直接按索引查找, 所以查找时较快
---|LinkedList: 链表实现, 增删快, 查找慢
由于链表实现, 增加时只要让前一个元素记住自己就可以, 删除时让前一个元素记 住后一个元素, 后一个元素记住前一个元素. 这样的增删效率较高但查询时需要一 个一个的遍历, 所以效率较低
---|Vector: 和ArrayList原理相同, 但线程安全, 效率略低和ArrayList实现方式相同, 但考虑了线程安 全问题, 所以效率略低
---|Set: 无存储顺序, 不可重复
---|HashSet
---|TreeSet
---|LinkedHashSet
---| Map: 键值对
---|HashMap
---|TreeMap
---|HashTable
---|LinkedHashMap
1.4 集合的使用场景
Collection 我们需要保存若干个对象的时候使用集合。
List
如果我们需要保留存储顺序, 并且保留重复元素, 使用List.
如果查询较多, 那么使用ArrayList
如果存取较多, 那么使用LinkedList
如果需要线程安全, 那么使用Vector
Set
如果我们不需要保留存储顺序, 并且需要去掉重复元素, 使用Set.
如果我们需要将元素排序, 那么使用TreeSet
如果我们不需要排序, 使用HashSet, HashSet比TreeSet效率高.
如果我们需要保留存储顺序, 又要过滤重复元素, 那么使用LinkedHashSet
2. Collection:单列集合
Collection接口有两个子接口:
List(链表|线性表)
Set(集)
特点:
Collection中描述的是集合共有的功能(CRUD)
List可存放重复元素,元素存取是有序的
Set不可以存放重复元素,元素存取是无序的
java.util.Collection
---| Collection 描述所有接口的共性
----| List接口 可以有重复元素的集合
----| Set 接口 不可以有重复元素的集合
学习集合对象
学习Collection中的共性方法,多个容器在不断向上抽取就出现了该体系。发现Collection接口中具有所有容器都具备的共性方法。查阅API时,就可以直接看该接口中的方法。并创建其子类对象对集合进行基本应用。当要使用集合对象中特有的方法,在查看子类具体内容。
查看api 文档Collection在在java.util 中(注意是大写Collection)注意在现阶段遇到的 E T 之类的类型,需要暂时理解为object 因为涉及到了泛型.
创建集合对象,使用Collection中的List的具体实现类ArrayList, Collection coll=new Arraylist();
Collection接口中的共性方法
增加:
1:add() 将指定对象存储到容器中,add 方法的参数类型是Object 便于接收任意对象
2:addAll() 将指定集合中的元素添加到调用该方法和集合中
删除:
3:remove() 将指定的对象从集合中删除
4:removeAll() 将指定集合中的元素删除
修改
5:clear() 清空集合中的所有元素
判断
6:isEmpty() 判断集合是否为空
7:contains() 判断集合何中是否包含指定对象
8:containsAll() 判断集合中是否包含指定集合,使用equals()判断两个对象是否相等
获取: 9:int size() 返回集合容器的大小
转成数组10: toArray() 集合转换数组
2.1 List
---| Iterable 接口
Iterator iterator()
----| Collection 接口
------| List 接口 元素可以重复,允许在指定位置插入元素,并通过索引来访问元素
List集合特有方法
1:增加
void add(int index, E element) 指定位置添加元素
boolean addAll(int index, Collection c) 指定位置添加集合
2:删除
E remove(int index) 删除指定位置元素
3:修改
E set(int index, E element) 返回的是需要替换的集合中的元素
4:查找:
E get(int index) 注意: IndexOutOfBoundsException
int indexOf(Object o) // 找不到返回-1
lastIndexOf(Object o)
5:求子集合
List<E> subList(int fromIndex, int toIndex) // 不包含toIndex
2.1.1 ArrayList
--| Iterable
----| Collection
------| List
---------| ArrayList 底层采用数组实现,默认10。每次增长60%,((oldCapacity * 3)/2 + 1) 查询快,增删慢。
---------| LinkedList
ArrayList:实现原理:
数组实现, 查找快, 增删慢
数组为什么是查询快?因为数组的内存空间地址是连续的.
ArrayList底层维护了一个Object[] 用于存储对象,默认数组的长度是10。可以通过 new ArrayList(20)显式的指定用于存储对象的数组的长度。
当默认的或者指定的容量不够存储对象的时候,容量自动增长为原来的容量的1.5倍。
由于ArrayList是数组实现, 在增和删的时候会牵扯到数组增容, 以及拷贝元素. 所以慢。数组是可以直接按索引查找, 所以查找时较快。
可以考虑,假设向数组的0角标未知添加元素,那么原来的角标位置的元素需要整体往后移,并且数组可能还要增容,一旦增容,就需要要将老数组的内容拷贝到新数组中.所以数组的增删的效率是很低的。
2.1.2 Linkedlist
LinkedList:链表实现, 增删快, 查找慢
由于LinkedList:在内存中的地址不连续,需要让上一个元素记住下一个元素.所以每个元素中保存的有下一个元素的位置.虽然也有角标,但是查找的时候,需要从头往下找,显然是没有数组查找快的.但是,链表在插入新元素的时候,只需要让前一个元素记住新元素,让新元素记住下一个元素就可以了.所以插入很快.
由于链表实现, 增加时只要让前一个元素记住自己就可以, 删除时让前一个元素记住后一个元素, 后一个元素记住前一个元素. 这样的增删效率较高。但查询时需要一个一个的遍历, 所以效率较低。
特有方法
1:方法介绍
addFirst(E e)
addLast(E e)
getFirst()
getLast()
removeFirst()
removeLast()
如果集合中没有元素,获取或者删除元素抛出:NoSuchElementException
2:数据结构
1:栈 (1.6)
先进后出
push()
pop()
2:队列(双端队列1.5)
先进先出
offer()
poll()
3:返回逆序的迭代器对象
descendingIterator() 返回逆序的迭代器对象
ArrayList和 LinkedList的存储查找的优缺点:
1、ArrayList 是采用动态数组来存储元素的,它允许直接用下标号来直接查找对应的元素。但是,但是插入元素要涉及数组元素移动及内存的操作。总结:查找速度快,插入操作慢。
2、LinkedList 是采用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快
2.1.3 Vector
Vector: 描述的是一个线程安全的ArrayList。
ArrayList: 单线程效率高
Vector : 多线程安全的,所以效率低
特有的方法:
void addElement(E obj) 在集合末尾添加元素
E elementAt( int index) 返回指定角标的元素
Enumeration elements() 返回集合中的所有元素,封装到Enumeration对象中
Enumeration 接口:
boolean hasMoreElements() 测试此枚举是否包含更多的元素。
E nextElement() 如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素。
2.2 Set
Set:注重独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素
用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。
对象的相等性
引用到堆上同一个对象的两个引用是相等的。如果对两个引用调用hashCode方法,会得到相同的结果,如果对象所属的类没有覆盖Object的hashCode方法的话,hashCode会返回每个对象特有的序号(java是依据对象的内存地址计算出的此序号),所以两个不同的对象的hashCode值是不可能相等的。
如果想要让两个不同的Person对象视为相等的,就必须覆盖Object继下来的hashCode方法和equals方法,因为Object hashCode方法返回的是该对象的内存地址,所以必须重写hashCode方法,才能保证两个不同的对象具有相同的hashCode,同时也需要两个不同对象比较equals方法会返回true
该集合中没有特有的方法,直接继承自Collection。
---| Itreable 接口 实现该接口可以使用增强for循环
---| Collection 描述所有集合共性的接口
---| List接口 可以有重复元素的集合
---| ArrayList
---| LinkedList
---| Set接口 不可以有重复元素的集合
2.2.1 HashSet
---| Itreable 接口 实现该接口可以使用增强for循环
---| Collection 描述所有集合共性的接口
---| List接口 可以有重复元素的集合
---| ArrayList
---| LinkedList
---| Set接口 不可以有重复元素的集合
---| HashSet 线程不安全,存取速度快。底层是以哈希表实现的。
HashSet
哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 是按照哈希值来存的所以取数据也是按照哈希值取得。
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的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。
hashtable
HashSet:通过hashCode值来确定元素在内存中的位置。一个hashCode位置上可以存放多个元素。
当hashcode() 值相同equals() 返回为true 时,hashset 集合认为这两个元素是相同的元素.只存储一个(重复元素无法放入)。调用原理:先判断hashcode 方法的值,如果相同才会去判断equals 如果不相同,是不会调用equals方法的。
HashSet到底是如何判断两个元素重复。
通过hashCode方法和equals方法来保证元素的唯一性,add()返回的是boolean类型
判断两个元素是否相同,先要判断元素的hashCode值是否一致,只有在该值一致的情况下,才会判断equals方法,如果存储在HashSet中的两个对象hashCode方法的值相同equals方法返回的结果是true,那么HashSet认为这两个元素是相同元素,只存储一个(重复元素无法存入)。
注意:HashSet集合在判断元素是否相同先判断hashCode方法,如果相同才会判断equals。如果不相同,是不会调用equals方法的。
HashSet 和ArrayList集合都有判断元素是否相同的方法,
boolean contains(Object o)
HashSet使用hashCode和equals方法,ArrayList使用了equals方法
2.2.2 TreeSet
2.2.3 LinkedHashSet
2.3 迭代器
为了方便的处理集合中的元素,Java中出现了一个对象,该对象提供了一些方法专门处理集合中的元素.例如删除和获取集合中的元素.该对象就叫做迭代器(Iterator).
对 Collection 进行迭代的类,称其为迭代器。还是面向对象的思想,专业对象做专业的事情,迭代器就是专门取出集合元素的对象。但是该对象比较特殊,不能直接创建对象(通过new),该对象是以内部类的形式存在于每个集合类的内部。
如何获取迭代器?Collection接口中定义了获取集合类迭代器的方法(iterator()),所以所有的Collection体系集合都可以获取自身的迭代器。
正是由于每一个容器都有取出元素的功能。这些功能定义都一样,只不过实现的具体方式不同(因为每一个容器的数据结构不一样)所以对共性的取出功能进行了抽取,从而出现了Iterator接口。而每一个容器都在其内部对该接口进行了内部类的实现。也就是将取出方式的细节进行封装。
2.3.1 Iterable
Jdk1.5之后添加的新接口, Collection的父接口. 实现了Iterable的类就是可迭代的.并且支持增强for循环。该接口只有一个方法即获取迭代器的方法 iterator()可以获取每个容器自身的迭代器Iterator。(Collection)集合容器都需要获取迭代器(Iterator)于是在5.0后又进行了抽取将获取容器迭代器的iterator()方法放入到了Iterable接口中。Collection接口进程Iterable,所以Collection体系都具备获取自身迭代器的方法,只不过每个子类集合都进行了重写(因为数据结构不同)
2.3.2 Iterator
Iterator iterator() 返回该集合的迭代器对象
该类主要用于遍历集合对象,该类描述了遍历集合的常见方法
1:java.lang. Itreable
---| Itreable 接口 实现该接口可以使用增强for循环
---| Collection 描述所有集合共性的接口
---| List接口 可以有重复元素的集合
---| Set接口 不可以有重复元素的集合
public interface Iterable<T>
Itreable 该接口仅有一个方法,用于返回集合迭代器对象。
1: Iterator<T> iterator() 返回集合的迭代器对象
Iterator接口定义的方法
Itreator 该接口是集合的迭代器接口类,定义了常见的迭代方法
1:boolean hasNext()
判断集合中是否有元素,如果有元素可以迭代,就返回true。
2: E next()
返回迭代的下一个元素,注意: 如果没有下一个元素时,调用next元素会抛出NoSuchElementException
3: void remove()
从迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作)。
2.3.3 迭代器遍历
---| Iterator
hasNext()
next()
remove()
------| ListIterator Iterator子接口 List专属的迭代器
add(E e) 将指定的元素插入列表(可选操作)。该元素直接插入到 next 返回的下一个元素的前面
void set(E o) 用指定元素替换 next 或 previous 返回的最后一个元素
hasPrevious() 逆向遍历列表,列表迭代器有多个元素,则返回 true。
previous() 返回列表中的前一个元素。
Iterator在迭代时,只能对元素进行获取(next())和删除(remove())的操作。
对于 Iterator 的子接口ListIterator 在迭代list 集合时,还可以对元素进行添加(add(obj)),修改set(obj)的操作。
2.3.4 List特有的迭代器ListIterator
3. Map:键值对
如果程序中存储了几百万个学生,而且经常需要使用学号来搜索某个学生,那么这个需求有效的数据结构就是Map。Map是一种依照键(key)存储元素的容器,键(key)很像下标,在List中下标是整数。在Map中键(key)可以使任意类型的对象。Map中不能有重复的键(Key),每个键(key)都有一个对应的值(value)。一个键(key)和它对应的值构成map集合中的一个元素。
Map中的元素是两个对象,一个对象作为键,一个对象作为值。键不可以重复,但是值可以重复。
看顶层共性方法找子类特有对象.
Map与Collection在集合框架中属并列存在
Map存储的是键值对
Map存储元素使用put方法,Collection使用add方法
Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素
Map集合中键要保证唯一性
也就是Collection是单列集合, Map 是双列集合。
总结:
Map一次存一对元素, Collection 一次存一个。Map 的键不能重复,保证唯一。
Map 一次存入一对元素,是以键值对的形式存在.键与值存在映射关系.一定要保证键的唯一性.
查看api文档:
interface Map<K,V>
K - 此映射所维护的键的类型
V - 映射值的类型
概念:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
特点:Key和Value是1对1的关系,如:门牌号 :家 老公:老婆
双列集合
Map学习体系:
---| Map 接口 将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。
---| HashMap 采用哈希表实现,所以无序
---| TreeMap 可以对健进行排序
---|Hashtable:
底层是哈希表数据结构,线程是同步的,不可以存入null键,null值。
效率较低,被HashMap 替代。
---|HashMap:
底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。
要保证键的唯一性,需要覆盖hashCode方法,和equals方法。
---| LinkedHashMap:
该子类基于哈希表又融入了链表。可以Map集合进行增删提高效率。
---|TreeMap:
底层是二叉树数据结构。可以对map集合中的键进行排序。需要使用Comparable或者Comparator 进行比较排序。return 0,来判断键的唯一性。
常见方法
1、添加:
1、V put(K key, V value) (可以相同的key值,但是添加的value值会覆
盖前面的,返回值是前一个,如果没有就返回null)
2、putAll(Map<? extends K,? extends V> m) 从指定映射中将所有映射关
系复制到此映射中(可选操作)。
2、删除
1、remove() 删除关联对象,指定key对象
2、clear() 清空集合对象
3、获取
1:value get(key); 可以用于判断键是否存在的情况。当指定的键不存在的时候,返
回的是null。
3、判断:
1、boolean isEmpty() 长度为0返回true否则false
2、boolean containsKey(Object key) 判断集合中是否包含指定的key
3、boolean containsValue(Object value) 判断集合中是否包含指定的value
4、长度:
Int size()
3.1 HashMap
底层是哈希表数据结构,线程是不同步的,可以存入null键,null值。要保证键的唯一性,需要覆盖hashCode方法,和equals方法。
3.2 TreeMap
TreeMap的排序,TreeMap可以对集合中的键进行排序。如何实现键的排序?
方式一:元素自身具备比较性
和TreeSet一样原理,需要让存储在键位置的对象实现Comparable接口,重写compareTo方法,也就是让元素自身具备比较性,这种方式叫做元素的自然排序也叫做默认排序。
方式二:容器具备比较性
当元素自身不具备比较性,或者自身具备的比较性不是所需要的。那么此时可以让容器自身具备。需要定义一个类实现接口Comparator,重写compare方法,并将该接口的子类实例对象作为参数传递给TreeMap集合的构造方法。
注意:当Comparable比较方式和Comparator比较方式同时存在时,以Comparator的比较方式为主;
注意:在重写compareTo或者compare方法时,必须要明确比较的主要条件相等时要比较次要条件。(假设姓名和年龄一直的人为相同的人,如果想要对人按照年龄的大小来排序,如果年龄相同的人,需要如何处理?不能直接return 0,以为可能姓名不同(年龄相同姓名不同的人是不同的人)。此时就需要进行次要条件判断(需要判断姓名),只有姓名和年龄同时相等的才可以返回0.)
通过return 0来判断唯一性。
注意:Set的元素不可重复,Map的键不可重复,如果存入重复元素如何处理
Set元素重复元素不能存入add方法返回false
Map的重复健将覆盖旧键,将旧值返回。
3.3 HashTable
3.4 LinkedHashMap
4. Collections与Arrays
集合框架中的工具类:特点:该工具类中的方法都是静态的。
Collections:常见方法:
1, 对list进行二分查找:
前提该集合一定要有序。
int binarySearch(list,key);
//必须根据元素自然顺序对列表进行升级排序
//要求list 集合中的元素都是Comparable 的子类。
int binarySearch(list,key,Comparator);
2,对list集合进行排序。
sort(list);
//对list进行排序,其实使用的事list容器中的对象的compareTo方法
sort(list,comaprator);
//按照指定比较器进行排序
3,对集合取最大值或者最小值。
max(Collection)
max(Collection,comparator)
min(Collection)
min(Collection,comparator)
4,对list集合进行反转。
reverse(list);
5,对比较方式进行强行逆转。
Comparator reverseOrder();
Comparator reverseOrder(Comparator);
6,对list集合中的元素进行位置的置换。
swap(list,x,y);
7,对list集合进行元素的替换。如果被替换的元素不存在,那么原集合不变。
replaceAll(list,old,new);
8,可以将不同步的集合变成同步的集合。
Set synchronizedSet(Set<T> s)
Map synchronizedMap(Map<K,V> m)
List synchronizedList(List<T> list)
9. 如果想要将集合变数组:
可以使用Collection 中的toArray 方法。注意:是Collection不是Collections工具类
传入指定的类型数组即可,该数组的长度最好为集合的size。
Arrays:用于对数组操作的工具类
1,二分查找,数组需要有序
binarySearch(int[])
binarySearch(double[])
2,数组排序
sort(int[])
sort(char[])……
2, 将数组变成字符串。
toString(int[])
3, 复制数组。
copyOf();
4, 复制部分数组。
copyOfRange():
5, 比较两个数组是否相同。
equals(int[],int[]);
6, 将数组变成集合。
List asList(T[]);
这样可以通过集合的操作来操作数组中元素,
但是不可以使用增删方法,add,remove。因为数组长度是固定的,会出现
UnsupportOperationExcetion。
可以使用的方法:contains,indexOf。。。
如果数组中存入的基本数据类型,那么asList会将数组实体作为集合中的元素。
如果数组中的存入的引用数据类型,那么asList会将数组中的元素作为集合中
的元素。
明天打算做的事情:
继续看数据库和Java的内容
遇到的问题:
收获:
评论