1. 集合框架
- 为什么出现集合类?
面向对象对事物的体现都是以对象的形式,为了方便对多个对象的操作,就对对象进行存储。
集合就是存储对象最常用的一种方式。- 数组和集合都是容器,两者有何不同?
(1)数组长度固定,而集合长度是可变的。
(2)数组值可以存储对象,还可以存储基本数据类型;而集合只能存储对象。
(3)数组存储数据类型是固定的,而集合存储的数据类型不固定。- 集合类的特点
(1)集合只能存储对象。
(2)集合的长度是可变的。
(3)集合可以存储不同类型的对象。1. Collection:顶层接口
(1)List:集合
元素是有序的(元素带角标索引),可以有重复元素,可以有null元素。
a:ArrayList
数据结构:数组。
特点:
①查询速度快(因为带角标),但是增删速度稍慢。(因为当元素多时,增删一个元素则所有元素的角标都得改变)
②线程不同步。
③默认长度是10,当超过长度时,按50%延长集合长度。
b:LinkedList
数据结构:链表(即后面一个元素记录前一个)。
特点:
①查询速度慢。(因为每个元素只知道前面一个元素)
②增删速度快。(因为元素再多,增删一个,只要让其前后的元素重新相连即可)
③线程不同步。
c:Vector
数据结构:数组。
特点:
①查询和增删速度都很慢。
②线程同步。
③默认长度是10,当超过长度时,按100%延长集合长度。
注意:
①Vector功能跟ArrayList功能一模一样,已被ArrayList替代。
②对于List集合,无论是add、contains、还是remove方法,判断元素是否相同,都是通过复写equals方法来判断!
一般情况下,使用哪种List接口下的实现类呢?
①如果要求增删快,考虑使用LinkedList。
②如果要求查询快,考虑使用ArrayList。
③如果要求线程安全,考虑使用Vector。
(2)Set:集合
元素唯一。可以有null元素。
a:HashSet
数据结构:哈希表。
特点:
①存取速度快。
②元素唯一。
③线程不同步。
保证性元素唯一的原理:
先判断元素的hashCode值是否相同,再判断两元素的equals方法是否为true(往HashSet里面存的自定义元素要复写hashCode和equals方法, 以保证元素的唯一性!)
b:TreeSet
数据结构:二叉树。
特点:
①元素有序。
②线程不同步。
保证元素唯一性的依据:compareTo()方法return 0。
注意:
①HashSet
为了保证元素的唯一性,我们通常在往HashSet集合里面存储元素时,在定义对象的类中通常复写hashCode和equals方法。
HashSet是如何保证元素唯一性的呢?
如果两元素的hashCode值不同,则不会调用equals方法。
如果两元素的hashCode值相同,则继续判断equals是否返回true。
②TreeSet
TreeSet要求往里面存的元素具备比较性,否则会报错。
TreeSet排序的第一种方式:让元素自身具备比较性。
定义对象类,实现Compareble接口,复写compareTo方法,此方式是元素的自然顺序。- Map:顶层接口
存储方式:键值对,键唯一。
Set集合底层使用了Map集合(Set和Map很相似)。
注意:
Map集合没有迭代器,要取出元素必须先将Map集合转换成Set集合才能遍历元素。
(1)HashTable
数据结构:哈希表。
特点:
①键和值都不能为null。
②效率低。
③线程同步。
保证键的唯一性:用作键的对象必须实现hashCode和equals方法。
(2)HashMap
数据结构:哈希表。
特点:
①键和值可以为null。
②效率高。
③线程不同步。
保证元素唯一性:先判断元素的hashCode值是否相同,再判断两元素的equals方法是否为true。(往HashSet里面存的自定义元素要复写hashCode和equals方法,以保证元素的唯一性!)
(3)TreeMap
数据结构:二叉树。
特点:
①键和值可以为null。
②线程不同步。- Iterator:迭代器
Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构
迭代器取代了Enumeration(枚举)。
(1)迭代器和枚举的区别
①迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的collection移除元素。
②方法名称得到了改进,简化书写。
3. Map集合和Collection集合的区别?
- Map中存储是键值对。Collection中存储是单个元素。
- Map的存储使用的put方法。Collection存储使用的是add方法。
- Map集合没有迭代器,Map的取出,是将Map转成Set,再使用迭代器取出。Collection取出,使用就是迭代器。
选择方式:- 如果对象很多,必须使用集合存储。
- 如果元素存在着映射关系,可以优先考虑使用Map存储或者用数组。
- 如果没有映射关系,可以使用Collection存储。
4. 迭代器:Iterator(Map集合没有迭代器)
- 迭代器就是取出集合元素的方式
- 获取迭代器的方法
Iterator<E> iterator():返回在此 collection的元素上进行迭代的迭代器。
Iterator<E> iterator():返回在此 set 中的元素上进行迭代的迭代器。 - 迭代器方法
boolean hasNext():如果仍有元素可以迭代,则返回 true。
E next():返回迭代的下一个元素。
void remove():从迭代器指向的collection中移除迭代器返回的最后一个元素(可选操作)。
5. 堆栈和队列
堆栈:先进后出,比如:穿衣服。
队列:先进先出,比如:排队打饭。
6. 集合类各种容器的使用注意细节
- 迭代器
(1)迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。也就是在迭代循环中调用一次next方法一次就要hasNext判断一次。
比如:语句sop(it.next()+"..."+it.next())会发生上述异常。
(2)迭代器的next方法返回值类型是Object,所以要记得类型转换,应用泛型后就不用强转。
- List集合
(1)List集合元素带角标,所以元素有序。
(2)List集合可以含重复元素,也可以含null。
(3)List集合有迭代器Iterator,还有一个特有迭代器列表ListIterator。
(4)List集合中判断元素是否相同都是用equals方法,无论contains、remove都依赖equals方法。 - Set集合
(1)Set接口里元素是唯一的,可以包含null。
(2)Set集合只有一种取出方式,就是迭代器Iterator。
(3)HashSet
①数据结构:哈希表。元素是无序的,唯一的。
②线程不同步。
(4)TreeSet
①数据结构:二叉树。元素是有序的,唯一的。
②线程不同步。
③TreeSet集合要求往集合里存放的元素自身具备比较性,否则会报错。 - Map集合
(1)Hashtable
哈希表结构,线程安全的,键和值不能为null。
(2)HashMap
哈希表结构,线程不安全的,键和值可以为null。
(3)LinkedHashMap
链表和哈希表,线程不安全。
(4)TreeMap
二叉树,线程不安全的。
6. 面试题(集合框架)
如果你想将一组对象按一定顺序存取,在不考虑并发访问的情况下会使用C , 反之则会使用A;
如果你想存储一组无序但唯一的对象,你会使用B;
如果你想按关键字对对象进行存取,在不考虑并发访问的情况下会使用D ,反之则会使用E。
A. Vector
B. HashSet
C. ArrayList
D. HashMap
E. Hashtable
7. 泛型
- 为什么会出现泛型?
(1)因为集合存放的数据类型不固定,故往集合里面存放元素时,存在安全隐患。
(如果在定义集合时,可以想定义数组一样指定数据类型,那么就可以解决该类安全问题)
(2)JDK1.5后出现了泛型,用于解决集合框架的安全问题。
(3)泛型是一个类型安全机制。
- 泛型定义格式
通过<>来定义要操作的引用数据类型。
比如:ArrayList<String> al = new ArrayList<String>; - 泛型的好处
(1)将运行时期出现的ClassCastException(类型转换异常)问题转移到编译时期。
(2)避免了强制转换的麻烦。 - 泛型的形式
(1)泛型类:即自定义泛型类。
A:当类中要操作的引用数据类型不确定时,早期定义Object来完成扩展,现在定义泛型来完成。
B:局限性,泛型类定义的泛型,在整个类中有效,如果该泛型类的方法被调用,当泛型类的对象明确要操作的类型后,所有要操作的类型就被固定。
(2)泛型方法:泛型放在返回值前面,修饰符的后面。
A:为了避免泛型类的局限性,让不同方法可以操作不同的类型,而且类型还不确定,则可以将泛型定义在方法上。
B:特殊之处,静态方法不可以访问类上定义的泛型。
如果静态方法操作的应用数据类型不确定,可以将泛型定义在静态方法上。
(3)泛型接口
当泛型定义在接口上时,则子类中要指定实现接口类型,同时还可以子类也可以定义为泛型类。 - 泛型的高级应用:?通配符
(1)当指定两种泛型的集合,则迭代时也要定义两种泛型的迭代器,有点麻烦,此时可通过将迭代器的泛型改为?
如:Iterator<?> it=al.iterator();
(2)两种泛型限定
向上限定: ? extends E; E可以接收E类型或者E的子类。
向下限定: ? super E; E可以接收E类型或者E的父类。
8. 高级for循环
- 高级for循环,只用于集合和数组的遍历,集合只能用Collection不能用Map集合。
只有把Map集合转化成Set集合,才能用for循环。- 格式
for(数据类型 变量名:被遍历的集合(Collection)或者数组){
}- 局限性
(1)必须要有遍历的目标。
(2)对集合或者数组进行遍历时,只能获取集合元素,不能对集合元素进行操作。
(3)迭代器除了遍历,还可以进行remove操作集合中的元素。
(4)列表迭代器还可以在遍历过程中进行增删改查的操作。- 传统for循环和高级for循环的区别
(1)高级for循环有一个局限性,就是必须要有遍历的目标(集合或者数组)。
(2)遍历数组时建议使用传统for循环,因为可以定义角标,比如打印100次helloworld时用传统for循环方便。
9. 可变参数
- 数组的可变参数
格式:
int... arr- 方法的可变参数
格式:
public static void show(String str,int... arr){
}
注意:可变参数一定要放在参数列表的最后面。
10. 静态导入
import static java.util.Arrays.* :导入的是Arrays这个类中所有的静态方法。
- 静态方法摘要
static <T> boolean addAll(Collection<? super T> c, T... elements):将所有指定元素添加到指定 collection 中。
static <T> void fill(List<? super T> list, T obj):使用指定元素替换指定列表中的所有元素。
static <T> boolean replaceAll(List<T> list, T oldVal, T newVal):使用另一个值替换列表中出现的所有某一指定值。
static void reverse(List<?> list):反转指定列表中元素的顺序。
static <T> Comparator<T> reverseOrder():返回一个比较器,它强行逆转实现了Comparable 接口的对象 collection 的自然顺序。
static <T> Comparator<T> reverseOrder(Comparator<T> cmp):返回一个比较器,它强行逆转指定比较器的顺序。- Collections类特牛的方法
集合有一个共同的缺点,那就是线程不安全,被多线程操作时,容易出现问题,虽然可以自己加锁,但是麻烦。
Collections提供特牛的方法,就是给它一个不同步的集合,它返回一个同步的安全的集合。
static <T> Collection<T> synchronizedCollection(Collection<T> c):返回指定 collection 支持的同步(线程安全的)collection。
static <T> List<T> synchronizedList(List<T> list):返回指定列表支持的同步(线程安全的)列表。
static <K,V> Map<K,V> synchronizedMap(Map<K,V> m):返回由指定映射支持的同步(线程安全的)映射。
static <T> Set<T> synchronizedSet(Set<T> s):返回指定 set 支持的同步(线程安全的)set。
static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m):返回指定有序映射支持的同步(线程安全的)有序映射。
static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s):返回指定有序 set 支持的同步(线程安全的)有序 set。
11. Arrays类
此类包含用来操作数组(比如排序和搜索)的各种方法。里面都是静态方法。
- 静态方法摘要
static <T> List<T> asList(T... a):返回一个受指定数组支持的固定大小的列表。
注意:
(1)该方法将一个数组变成集合后,不可以使用集合的增删方法,因为数组的长度是固定的!
如果增删,则发生UnsupportedOprationException。(不支持操作异常)
(2)如果数组中的元素都是基本数据类型,则该数组变成集合时,会将该数组作为集合的一个元素出入集合。
(3)如果数组中的元素都是对象,如String,那么数组变成集合后,数组中的元素就直接转成集合中的元素。
12. 数组变集合以及集合变数组的对比
- 数组变集合
方法:static <T> List<T> asList(T... a):返回一个受指定数组支持的固定大小的列表。
好处:可以使用集合的思想和方法操作数组中的元素,数组是一个对象,但是数组中的功能很少。- 集合变数组
方法:Collction中的toArray方法。
好处:可以限定对集合元素的操作,防止对集合的元素进行增删,因为数组长度是固定的。
13. Collections类和Arrays类的使用。(重点)
- Collections
(1)排序
(2)二分查找
(3)反转- Arrays
(1)把数组变成字符串输出
(2)排序
(3)二分查找
14. Runtime
- 每个 Java 应用程序都有一个 Runtime类实例,使应用程序能够与其运行的环境相连接。
- 通过 getRuntime 方法获取当前运行时。
- 应用程序不能创建自己的 Runtime 类实例。
- 该类没有构造函数,也就是它不能直接创建对象。
- 该类是单例设计模式,保证在内存中只有一个对象。
- 方法摘要
Process exec(String command):在单独的进程中执行指定的字符串命令。
void gc():运行垃圾回收器。
static Runtime getRuntime():返回与当前 Java 应用程序相关的运行时对象。
void exit(int status):通过启动虚拟机的关闭序列,终止当前正在运行的 Java 虚拟机。
15. Date
- 构造方法
Date():分配Date对象并初始化此对象,表示分配它的时间(精确到毫秒)。
Date(long date):分配Date对象并初始化此对象,表示自标准基准时间以来的指定毫秒数。
(标准基准时间:称为“历元(epoch)”,即1970年1月1日00:00:00GMT)- 方法摘要
int compareTo(Date anotherDate):比较两个日期的顺序。
boolean equals(Object obj):比较两个日期的相等性。
16. Calendar
- 直接子类: GregorianCalendar
- 构造方法
protected Calendar():构造一个带有默认时区和语言环境的 Calendar。
protected Calendar(TimeZone zone, Locale aLocale):构造一个带有指定时区和语言环境的 Calendar。- 方法摘要
static Calendar getInstance():使用默认时区和语言环境获得一个日历。