文章目录
- 泛型
-
- 1.泛型思想
- 2.泛型类
- 3.泛型方法
- 4.泛型高级用法
- 5.类型擦除
- 集合
-
- 1.集合框架
- 2.Iterator和Collection
-
- 2.1 Iterator(迭代器接口)
- 2.2 Collection接口
- 3.List集合
-
- 3.1 ArrayList
- 3.2 LinkedList
- 4.Set集合
-
- 4.1 HashSet
- 4.2 TreeSet
- 5.Queue集合和Deque接口
-
- 5.1 Queue(队列)
- 5.3 Deque接口
- 6.Map集合
泛型
1.泛型思想
泛型的本质是参数化类型,也就是说可以为类、接口或方法指定一个类型参数(注意类型是对象,不能是基本类型如int、double等),这意味着编写的代码可以对多种不同类型的对象重用。泛型提供了编译时类型安全检测机制,可防止插入错误的对象。因此泛型可以使程序更易读,也更安全。由于把对象“丢进”集合时,集合丢失了对象的状态信息,集合只知道它盛装的是 Object,因此取出集合元素后通常还需要进行强制类型转换。这种强制类型转换既增加了编程的复杂度,也可能引发 ClassCastException 异常。
先看一个简单的例子
List list = new ArrayList();
List<String> list = new ArrayList<String>(); // 之后的集合初始化基本都会使用泛型
List<String> list = new ArrayList<>(); // 这样写更加简洁
可以很明显的发现使用泛型进行初始化可以很容易的知到list中存储的是String对象并且只能存储String对象,显然第一行代码做不到这一点,这便是泛型的易读性和安全性。
2.泛型类
按照约定,类型参数名使用单个大写字母表示,常用的有E(表示元素)、K(表示键)、N(表示数字)、T(表示类型)、V(表示值)。不过下面的表示不太标准。
//定义一个泛型类的标准格式
public class Stu<N, A, S> {
private N name; // 姓名
private A age; // 年龄
// 创建类的构造函数
public Stu(N name, A age, S sex) {
this.name = name;
this.age = age;
}
// 下面是上面3个属性的setter/getter方法
public N getName() {
return name;
}
public void setName(N name) {
this.name = name;
}
public A getAge() {
return age;
}
public void setAge(A age) {
this.age = age;
}
}
Stu<String, Integer> stu = new Stu<String, Integer>("kk", 3); // 实例化对象
String name = stu.getName();
Integer age = stu.getAge();
// 获取学生姓名、年龄时,不需要类型转换,程序隐式地将 Object 类型的数据转换为相应的数据类型。
3.泛型方法
// 泛型方法 注意定义方法时的格式。 泛型方法所在的类可以是泛型类,也可以不是泛型类
public static <E> void printArray( E[] inputArray )// 可以有多个参数
{
// 输出数组元素
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
System.out.println();
}
class.<E>.printArray(Obj);// 调用。也可以这样写class.printArray(Obj);
//========有返回值的方法定义格式========//
public static <E> E printArray( E[] inputArray )// 可以有多个参数
{
}
4.泛型高级用法
// 1.限制泛型可用类型
// 限制ListClass的泛型类型必须实现List接口
public class ListClass<T extends List> {
public static void main(String[] args) {
// 实例化使用ArrayList的泛型类ListClass,正确
ListClass<ArrayList> lc1 = new ListClass<ArrayList>();
// 实例化使用LinkedList的泛型类LlstClass,正确
ListClass<LinkedList> lc2 = new ListClass<LinkedList>();
// 实例化使用HashMap的泛型类ListClass,错误,因为HasMap没有实现List接口
// ListClass<HashMap> lc3=new ListClass<HashMap>();
}
}
// 2.使用类型通配符
A<? extends List>a = null;
a = new A<ArrayList>(); // 正确
b = new A<LinkedList>(); // 正确
c = new A<HashMap>(); // 错误
T<?> d = null; //改写为这种形式,则上面的都正确
5.类型擦除
当实例化泛型类型时,编译器使用一种叫类型擦除(type erasure)的技术转换这些类型。在编译时,编译器将清除类和方法中所有与类型参数有关的信息。类型擦除可让使用泛型的Java应用程序与之前不使用泛型类型的Java类库和应用程序兼容。
例如,Node被转换成 Node,它称为源类型(raw type)。源类型是不带任何类型参数的泛型类或接口名。这说明在运行时找不到泛型类使用的是什么类型。因此下面的操作都会出现错误:
public class A<E>{
if(item instance E){...}
E item1 = new E();
E[] item2 = new E[10];
E obj = (E) new Object();
}
这篇文章的末尾详细的解释了类型擦除的机制【转载】Java泛型详解
集合
1.集合框架
先上图,集合框架中的接口和实现类。
从两张集合框架图可以看到,Java集合框架主要包括两种类型的容器,一种是集合(Collection),存储一种元素的集合;另一种是映射(Map),存储键/值对映射。
集合接口
接口 | 描述 |
---|---|
Iterable和Iterator的区别和联系 | https://blog.csdn.net/qq_32224047/article/details/106314992 注意Collection继承的是Iterable接口 |
Collection | Collection是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素, Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。Collection 接口存储一组不唯一,无序的对象。 |
List | 是最常用的接口。是有序集合,允许有相同的元素。使用 List 能够精确地控制每个元素插入的位置,用户能够使用索引(元素在 List 中的位置,类似于数组下标)来访问 List 中的元素,与数组类似。 |
Set | Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素。Set 接口存储一组唯一,无序的对象。 |
SortedSet | 继承于Set保存有序的集合。 |
Queue | Queue 是 Java 提供的队列实现,有点类似于 List。 |
Deque | 是 Queue 的一个子接口,为双向队列。 |
Map | Map 接口存储一组键值对象,提供key(键)到value(值)的映射。 |
SortedMap | 继承于 Map,使 Key 保持在升序排列。 |
RandomAccess | 《Java集合系列-RandomAccess》 写的很详细 |
集合实现类
类名称 | 描述 |
---|---|
AbstractCollection | 实现了大部分的集合接口 |
AbstractList | 继承于AbstractCollection 并且实现了大部分List接口 |
ArrayList | 该类也是实现了List的接口,实现了可变大小的数组,随机访问和遍历元素时,提供更好的性能,但插入删除效率低 |
AbstractSequentialList | 继承于 AbstractList ,提供了对数据元素的链式访问而不是随机访问 |
LinkedList | 该类实现了List接口,允许有null(空)元素,主要用于创建链表数据结构。LinkedList 查找效率低 |
AbstractSet | 继承于AbstractCollection 并且实现了大部分Set接口 |
HashSet | 该类实现了Set接口,不允许出现重复元素,不保证集合中元素的顺序,允许包含值为null的元素,但最多只能一个。 |
LinkedHashSet | 具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现 |
TreeSet | TreeSet 类同时实现了 Set 接口和 SortedSet 接口。SortedSet 接口是 Set 接口的子接口,可以实现对集合进行自然排序,因此使用 TreeSet 类实现的 Set 接口默认情况下是升序排序 |
AbstractMap | 实现了大部分的Map接口 |
HashMap | HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。该类实现了Map接口,根据键的HashCode值存储数据,具有很快的访问速度,最多允许一条记录的键为null,不支持线程同步。 |
TreeMap | 继承AbstractMap,并且使用一颗树 |
WeakHashMap | 继承AbstractMap类,使用弱密钥的哈希表 |
LinkedHashMap | 继承于HashMap,使用元素的自然顺序对元素进行排序 |
IdentityHashMap | 继承AbstractMap类,比较文档时使用引用相等 |
2.Iterator和Collection
首先从上面的框架图可以看出Iterable(Iterator)和Collection两个类里的方法都可以被List、Set和Queue集合调用(相同的方法就不重复总结了)。
2.1 Iterator(迭代器接口)
方法 | 作用 |
---|---|
boolean hasNext() | 如果存在另一个可访问的元素,返回true |
E next() | 返回将要访问的下一个对象。如果已经到达了集合的末尾,将抛出一个NoSuchElementException异常 |
void remove() | 删除上次访问的对象。这个方法必须紧跟在访问一个元素(next())后执行。如果上次访问之后集合已经发生了变化,将抛出IllegalStateException异常 |
default void forEachRemaining(Consumer<? super E> action) | 访问元素,并传递到指定的动作(如lambda表达式),直到再没有更多元素,或者这个动作抛出一个异常 |
遍历集合:
// 简洁的for循环 for each
ArrayList<String> list = new ArrayList<>();
for(String element : list){} // "for each" 可以处理任何实现了Iterable接口的对象
//而调用上面的forEachRemaining方法可以不写循环
Iterator<String> iterator = list.iterator(); // 初始化一个迭代器对象
iterator.forEachRemaining(element -> do something with element);
Java集合类库中的迭代器与C++(根据数组索引建模)等的有所不同。Java迭代器查找操作与位置变更紧密耦合,查找一个元素的唯一方法是调用next,在执行查找操作的同时,迭代器的位置会随之向前移动。因此,可以认为Java迭代器位于两个元素之间,当调用next时,迭代器就越过下一个元素。并返回刚刚越过的元素的引用。
2.2 Collection接口
方法 | 作用 |
---|---|
Iterator< E> iterator() | 返回一个 Iterator 对象,用于遍历集合中的元素 |
int size() | 返回集合中元素的个数 |
boolean isEmpty() | 集合为空则返回true |
boolean add(E e) & boolean addAll(Collection c) | 向集合中添加一个元素或c中的所有元素。如果集合对象被添加操作改变了,则返回 true |
Object[] toArray() | 把集合转换为一个数组,所有的集合元素变成对应的数组元素 |
void clear() | 清除集合中的所有元素,将集合长度变为 0 |
boolean contains(Object o) & boolean containsAll(Collection c) | 判断集合中是否存在指定元素或c中所有元素 |
boolean remove(Object o) | 从集合中删除一个指定元素,当集合中包含了一个或多个元素 o 时,该方法只删除第一个符合条件的元素,删除成功将返回 true |
boolean removeAll(Collection c) | 从集合中删除所有在集合 c 中出现的元素。如果该操作改变了调用该方法的集合,则该方法返回 true |
boolean retainAll(Collection c) | 从集合中删除集合 c 里不包含的元素。如果该操作改变了调用该方法的集合,则该方法返回 true |
3.List集合
可以发现Iterator没有add方法,但集合类库提供了一个继承自Iterator的子接口ListIterator,其中包含add方法,同时还可以反向遍历链表。
java.util.List
- ListIterator< E> listIterator() 返回一个列表迭代器,用来访问列表中的元素
- ListIterator< E> listIterator(int index) 返回一个列表迭代器,用来访问列表中的元素,第一次调用这个迭代器的next会返回给定索引的元素
java.util.ListIterator(初始化及使用与Iterator相同)
- void add(E element) 在当前位置添加一个元素
- E Previous() 返回前一个对象。如果已经到达了列表的头部,将抛出一个NoSuchElementException异常
- boolean hasPrevious() 反向迭代链表时。如果还有可以访问的元素,返回true
- void set(E element) 用新元素替换next或previous访问的上一个元素。如果上一个next或previous调用之后链表结构发生了变化,将抛出IllegalStateException异常
3.1 ArrayList
ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制。查找效率高,但添加或删除元素。
方法 | 作用 |
---|---|
ArrayList() & ArrayList(Collection<? extends E> elements) | 构造方法 |
E get(int index) | 获取此集合中指定索引位置的元素 |
E set(int index, Eelement) | 将此集合中指定索引位置的元素修改为 element 参数指定的对象,并返回此集合中指定索引位置的原元素。指定的索引必须是 List 集合的有效索引 |
int index(Object o) | 返回此集合中第一次出现指定元素的索引,如果此集合不包含该元素则返回 -1 |
int lastIndexOf(Object o) | 返回此集合中最后一次出现指定元素的索引,如果此集合不包含该元素,则返回 -1 |
List< E> subList(int fromlndex, int tolndex) | 返回一个新的集合,新集合中包含 [fromlndex,tolndex) 索引之间 |
3.2 LinkedList
LinkedList 类采用双向链表结构保存对象。需要频繁向集合中插入和删除元素时,使用 LinkedList 类比 ArrayList 类效果高,但是 LinkedList 类随机访问元素的速度则相对较慢。
方法 | 作用 |
---|---|
LinkedList() & LinkedList(Collection<? extends E> elements) | 构造方法 |
void addFirst(E e) & void addLast(E e) | 将指定元素添加到此集合的开头或末尾 |
E getFirst() & E getLast() | 返回此集合的第一个或最后一个元素 |
E removeFirst() & E removeLast() | 删除此集合的第一个或最后一个元素 |
4.Set集合
Set 集合类似于一个罐子,程序可以依次把多个对象“丢进”Set 集合,而 Set 集合通常不能记住元素的添加顺序。也就是说 Set 集合中的对象不按特定的方式排序,只是简单地把对象加入集合。Set 集合中不能包含重复的对象,并且最多只允许包含一个 null 元素。
4.1 HashSet
先康康散列集的设计思想 散列集简介
java.util.HashSet< E>
- HashSet() 构造一个空的散列集
- HashSet(Collection<? extends E>c) 构造一个包含指定 Collection 集合元素的新 Set 集合
- HashSet(int initialCapacity) 构造一个空的具有指定容量(桶数)的散列集
- HashSet(int initialCapacity, float loadFactor) 构造一个有指定容量和装填因子(0.0~1.0之间的一个数,确定散列表的填充百分比,当大于这个百分比时,散列表在进行再散列) 的散列集
Java.lang.Object
- int hashCode() 返回这个对象的散列码。散列码可以是任何整数,包括正数和负数。equals和hashCode的定义必须兼容,即如果x.equals(y)为true,则x.hashCode必须等于y.hashCode.
4.2 TreeSet
TreeSet 类同时实现了 Set 接口和 SortedSet 接口。SortedSet 接口是 Set 接口的子接口,可以实现对集合进行自然排序(默认为升序排序)。排序是用一个树的数据结构(目前是红黑树)完成的,每次将一个元素添加到树中,都会将其放置在正确的排序位置上。因此,遍历时(for each或迭代器)总是以有序的顺序访问每个元素。
TreeSet 只能对实现了 Comparable 接口的类对象进行排序,这些类有:
类 | 比较方式 |
---|---|
包装类(BigDecimal、Biglnteger、 Byte、Double、Float、Integer、Long 及 Short) | 按数字大小比较 |
Character | 按字符的 Unicode 值的数字大小比较 |
String | 按字符串中字符的 Unicode 值的数字大小比较 |
java.util.TreeSet< E>
- TreeSet() & TreeSet(Comparator<? super E> comparator) 构造一个空树集
- TreeSet(Collection<? extends E> elements) & TreeSet(SortedSet< E> s) 构造一个包含一个集合或有序集中的所有元素。(对于后一种情况,要使用同样的顺序)
java.util.SortedSet< E>
- Comparator<? super E> comparator() 返回用于对元素进行排序的比较器。如果元素用Comparable接口的compareTo方法进行比较则返回null
- E first() & E last() 返回有序集中最大或最小元素
- SortedSet subSet(E fromElement,E toElement) 返回一个新的集合,新集合包含原集合中 fromElement 对象与 toElement对象之间(不包含toElement对象)的所有对象
- SortedSet headSet(E toElement)返回一个新的集合,新集合包含原集合中 toElement 对象之前的所有对象。不包含 toElement 对象
-
SortedSet tailSet(E fromElement) 返回一个新的集合,新集合包含原集合中 fromElement 对象之后的所有对
象。包含 fromElement 对象
同时,从Java 6起,TreeSet类实现了NavigableSet接口,增加了几个查找元素以及反向遍历的便利方法
java.util.NavigableSet
- E higher(E value) & E lower(E value) 返回大于value的最小元素或小于value的最大元素,没有则返回null
- E ceiling(E value) & E floor(E value) 返回大于等于value的最小元素或小于等于value的最大元素,没有则返回null
- E pollFirst() & E pollLast() 删除并返回这个集中的最大或最小元素,集为空时返回null
- Iterator< E> descendingIterator() 返回一个按照递减顺序遍历元素的迭代器
5.Queue集合和Deque接口
5.1 Queue(队列)
队列允许你高效地在尾部添加元素,在头部删除元素。
方法 | 作用 |
---|---|
boolean add(E element) & boolean offer(E element) | 如果队列没满,将元素添加到队尾并返回true。如果队列已满,第一个方法会抛出IllegalStateException,而第二个方法返回false |
E remove() & E poll() | 队列不为空,删除并返回这个队列队头的元素。若队列为空,第一个方法会抛出NoSuchElementException,而第二个方法返回null |
E element() & E peek() | 队列不为空,返回这个队列队头的元素,但不删除。若队列为空,第一个方法会抛出NoSuchElementException,而第二个方法返回null |
**优先队列(PriorityQueue类)**继承自AbstractQueue类,其中的元素可以按照任意地顺序插入,但会按照有序的顺序进行检索(即总是从当前队列的最小元素开始操作)。这是因为优先队列使用了一种精巧且高效数据结构——堆(heap)。堆是一个可以自组织的二叉树,其添加(add)和删除(remove)操作可以让最小的元素移动到根,而不必花费时间对元素进行排序。与TreeSet一样,优先队列既可以保存实现了Comparable接口的类对象,也可以保存构造器中提供的Comparator对象。
java.util.PriorityQueue
- PriorityQueue() & PriorityQueue(int initialCapacity) 构造一个存放Comparable对象的优先队列
- PriorityQueue(int initialCapacity, Comparator<? super E> c) 构造一个优先队列,并使用指定的比较器对元素进行排序
5.3 Deque接口
Java 6引入了Deque接口,ArrayDeque和LinkedList实现了这个接口,这两个类都可以提供双端队列(deque),允许在头部和尾部都高效地添加或删除元素。
- void addFirst(E element) & void addLast(E element)
-
boolean offerFirst(E element) & boolean offerLast(E element)
将给定的对象添加到双端队列地队头或队尾。如果队列已满,第一组方法会抛出IllegalStateException,而第二组方法返回false
java.util.ArrayDeque
-
ArrayDeque() & ArrayDeque(int initialCapacity)
用初始容量16或给定的初始容量构造一个无限定双端队列
6.Map集合
Java类库为映射(map)提供了两个通用的实现:HashMap和TreeMap类,都实现了Map接口。
散列映射(HashMap)对键进行散射,树映射(TreeMap 实现了SortedMap接口)根据键的顺序将元素组织为一个搜索树(基于红黑树)。散列或比较函数只应用于键。散列效率快一些,如果不需要按照有序的顺序访问键,最好选择散列映射。
HashMap和TreeMap类的方法基本是相同的
方法 | 作用 |
---|---|
V get(Object key) | 获取与键关联的值或对象,没有则返回null |
V put(K key, V value) | 将一键值对放到映射中。如果键已存在,与键关联的旧对象将会被新的值取代,并返回关联的旧值。若之前没有这个键则返回null |
void putAll(Map<? extends K, ? extends V> entries) | 将指定Map中的 key-value 对复制到本Map中 |
boolean containsKey(Object key) | 查询 Map 中是否包含指定的 key,如果包含则返回 true |
boolean containsValue(Object value) | boolean containsValue(Object value) |
default void forEach(BiConsumer<? super K, ? super V> action) | 对键值对作相应的动作 |
boolean isEmpty() | 查询该 Map 是否为(即不包含任何 key-value 对,如果为空则返回 true |
int size() | 返回该 Map 里 key-value 对的个数 |
V remove(Object key) | 从 Map 集合中删除 key 对应的键-值对,返回 key 对应的 value,如果该 key 不存在,则返回 null |
boolean remove(Object key, Object value) | 这是 Java 8 新增的方法,删除指定 key、value 所对应的 key-value 对。如果从该 Map 中成功地删除该 key-value 对,该方法返回 true,否则返回 false |
void clear() | 删除该 Map 对象中的所有 key-value 对 |
java.util.HashMap<K,V>
- HashMap()
- HashMap(int initialCapacity)
-
HashMap(int initialCapacity, float loadFactor)
构造一个有指定容量和装填因子的空散列映射(0.0~1.0之间的一个数,确定散列表的填充百分比,当大于这个百分比时,散列表在进行再散列) 。默认的装填因子是0.75.
java.util.TreeMap< E>
- TreeMap() 为实现Comparable接口的键构造一个空的映射
- TreeMap(Comparator<? super K> c) 构造一个树映射,并使用指定的比较器对键进行排序
- TreeSet(Map<? extends k, ? extends v> entries) 构造一个包含entries所有映射的树映射
- TreeSet(SortedMap<? extends k, ? extends v> entries) 构造一个包含entries所有映射的树映射,且使用与给定有序映射相同的比较器
java.util.SortedMap<K, V>
- Comparator<? super K> comparator() 返回用于对元素进行排序的比较器。如果元素用Comparable接口的compareTo方法进行比较则返回null
- K firstKey() & E lastKey() 返回映射中最小或最大键