一、泛型
1、泛型类
泛型是带一个或者多个类型参数的类或接口。在Java集合框架中大多数的类和接口都是泛型类型。下面看一下泛型例子:
public class Fan<T>{
private T value;
public Fan(){};
public Fun(T value){
this.value=value;
}
public T getter(){
return value;
}
public void setter(T value){
this.value=value;
}
}
/******************************/
//测试类
/******************************/
public class Demo {
public static void main(String[] args){
Fun<Integer> fun=new Fun<>();
fun.setter(50);
System.out.println(fun.getter());
}
}
/*输出结果*/
//50
一旦创建了fun对象,就可以调用setter()方法设置其中的值(value),也就是Integer对象。但是如果输入的数据不与T在这里所代表的数据类型一致,就会发生错误。
从JavaSE7开始,在创建泛型类型时可以使用菱形语法,也就是在创建时只在前一个菱形括号里写类型标识符,如下:
Fun<Integer> fun=new Fun<>();
“T”在Java中叫做通配符,表示类型,除了T以外还有E(表示元素)、K(表示键)、N(表示数字)、V(表示值)、?(表示任意类型)。泛型可能具有多个类型参数,但在类或者接口的声明中,每个参数名必须是唯一的。
2、泛型方法
泛型方法是带类型参数的方法。类的成员方法和构造方法都可以定义为泛型方法。泛型方法的定义与泛型类的定义类似,只是类型参数的作用域不同。下面是例子:
public class Util{
public static <T> void swap(T[] array,int i,int j){
T temp=array[i];
array[i]=array[j];
array[j]=temp;
}
public static void main(String[] args) {
Integer[] numbers= {1,3,5,7};
Util.<Integer>swap(numbers,0,3);
for(Integer n:numbers) {
System.out.println(n+" ");//输出7 3 5 1
}
}
}
这里创建了一个Integer数组,调用Util的静态泛型方法swap()交换两个元素的位置。
二、集合框架
1、框架介绍
在编写面向对象的程序的时候,经常会遇到一些类型相同的对象,虽然可以用数组来存储这些对象,可是数组一经定义便不能改变大小。因此Java提供了一个集合框架来处理对象组,使得处理对象组更容易。
集合是指用来集中存放一组对象的一个对象,相当于一个容器,提供了保存、获取和操作其他元素的方法。Java集合框架由两种类型构成,一个是Collection,另一个是Map。它们是最基本 的接口,其下还有子接口,简化图如下:
Collection接口定义了集合操作的常用方法,基本可分为基本操作、批量操作、数组操作和流操作。特别要提的是集合类似于数组,因此也需要遍历,但是集合遍历一般用迭代器(Iterator)而不用循环。
2、List接口及实现类
List接口是Collection的子接口,实现一种线性表的子接口。存放在List中的元素都有下标,这个下标从0开始。List实现类包括ArrayList、LinkedList、Vector和Stack。List有E get(int index)(返回指定下标的元素)、E set(int index,E element)(修改指定下表处的元素)等常用方法。
1、ArrayList类
ArrayList是最常用的线性表实现类,通过数组实现的集合对象,它实现了一个变长的对象数组,其元素可以动态的增加和删除。它有如下的构造方法:
ArrayList():创建一个空的数组线性表对象,默认初始长度为10。
ArrayList(Collection c):用集合c中的元素创建一个数组线性表对象。
ArrayList(int initialCapacity):创建一个空的数组线性表对象,并指定初始容量。
下面是有关ArrayList类用法操作的程序例子:
List<String> bigCities=new ArrayList<>();
bigCities.add("上海");
bigCities.add("北京");
bigCities.add("广州");
System.out.println(bigCities.size);
bigCities.add(1,"伦敦");
bigCities.set(2,"纽约");
System.out.println(bigCities.contains("上海"));
System.out.println(bigCities);
System.out.println(bigCities.indexOf("巴黎"));
2、迭代器
Java迭代器是一种用于遍历集合类对象(如ArrayList、LinkedList、HashSet、HashMap等)中元素的工具。在Java中,所有的集合类都实现了接口java.util.Collection,而该接口中提供了一个Iterator方法,通过该方法可以返回一个迭代器对象。下面是Java中迭代器的使用方法:
1. 获取迭代器对象
使用集合类的iterator()方法获取迭代器对象,例如:
List<String> list = new ArrayList<>();
Iterator<String> it = list.iterator();
2. 遍历集合元素
使用while循环和hasNext()方法判断是否还有下一个元素,使用next()方法获取下一个元素,例如:
while(it.hasNext()) {
String element = it.next();
// do something with element
}
3. 删除集合元素
使用remove()方法删除集合中的元素,例如:
while(it.hasNext()) {
String element = it.next();
if(element.equals("foo")) {
it.remove();
}
}
需要注意的是,不能在使用迭代器遍历集合的过程中直接使用集合的add()、remove()等方法修改集合,否则会导致ConcurrentModificationException异常,应该使用迭代器提供的remove()方法来删除元素。
3、双向迭代器
双向迭代器(Bidirectional Iterator)是Java集合框架中的一种迭代器类型。它允许我们从集合的两个方向遍历元素。与单向迭代器(例如Iterator)不同,双向迭代器提供了向前迭代的能力。
在Java中,双向迭代器是Iterable接口的子接口之一,定义在java.util包中。它具有以下方法:
- next():返回列表中的下一个元素,并将迭代器位置向后移动一个元素。
- hasNext():如果列表中还有更多的元素并且迭代器没有到达末尾,则返回true。
- previous():返回列表中的前一个元素,并将迭代器位置向前移动一个元素。
- hasPrevious():如果列表中还有更多的元素并且迭代器没有到达开头,则返回true。
- remove():从列表中删除迭代器最后一个返回的元素。
- add():将指定的元素插入列表中。
- set():用指定的元素替换列表中最后一个返回的元素。
在使用双向迭代器时需要注意的是,只有实现了List接口的集合才支持双向迭代器。因为List接口中定义了许多与索引相关的方法,这些方法可以用来实现双向迭代器的向前遍历操作。
4、Vector类和Stack类
Vector类和Stack类都是Java中的集合类。Vector类是一种动态数组,可以根据需要自动增长和收缩。它与数组很像,但是可以自动调整大小,能够储存任何类型的数据。
Stack类则是Vector类的子类,它实现了后进先出的栈数据结构。Stack类提供了push()方法将元素压入栈,pop()方法将栈顶元素弹出,并提供了查看栈顶元素的peek()方法。
需要注意的是,由于Stack类是Vector类的子类,它所有的Vector类的方法和属性都可以使用。但是由于Stack类被设计为只用作栈的实现,因此建议只使用Stack类中提供的栈操作方法,并避免在Stack对象上使用Vector类中的其他方法来避免语义混淆。
3、Set接口以及实现类
Java中的Set接口表示一组不允许重复元素的集合,并且不保证集合中元素的顺序。Set接口派生自Collection接口,因此它继承了Collection的许多方法,比如add()、remove()和size()等。
Java中的常用Set实现类有以下几种:
1. HashSet:基于哈希表的Set实现类,不保证迭代顺序,但是可以快速查找元素,因此插入、删除和查找操作的时间复杂度为O(1)。
示例代码:
Set<String> set = new HashSet<>();
set.add("apple");
set.add("banana");
set.add("orange");
System.out.println(set); // 输出结果可能为[banana, orange, apple],顺序不定
2. TreeSet:基于红黑树的Set实现类,能够自然排序(根据元素实现Comparable接口的compareTo()方法或提供的Comparator比较器),因此迭代时元素按照升序排列,插入、删除、查找操作的时间复杂度为O(log n)。
示例代码:
Set<Integer> set = new TreeSet<>();
set.add(4);
set.add(10);
set.add(2);
System.out.println(set); // 输出结果为[2, 4, 10]
3. LinkedHashSet:基于哈希表和双向链表的Set实现类,维护插入顺序,因此迭代时元素按照插入顺序排列,插入、删除、查找操作的时间复杂度为O(1)。
示例代码:
Set<String> set = new LinkedHashSet<>();
set.add("apple");
set.add("banana");
set.add("orange");
System.out.println(set); // 输出结果为[apple, banana, orange]
Set接口提供了许多用于操作集合的方法,比如add()、remove()、contains()、isEmpty()和size()等,使用时需要根据具体情况选择合适的Set实现类。
4、Queue接口及实现类和Deque接口
队列(Queue)和双端队列(Deque)都是数据结构中用于存储数据元素的线性结构,它们最大的区别在于数据元素的出队方式。
双端队列不仅支持队列的基本操作,还支持头部元素的出队、尾部元素的进队和出队。这意味着双端队列可以同时支持队列和栈的特性,因此可以用于更多的数据操作场景。
Queue接口表示一种先进先出(FIFO)的数据结构。它提供了一系列方法,用于插入和删除元素,并可进行基本的检查操作。在Java中,Queue接口的实现类有很多,包括LinkedList、ArrayDeque等。
LinkedList实现了Queue接口,并且还实现了List接口,因此它可以被用作队列和列表,它其中可以存储空值。LinkedList是基于链表实现的,因此在处理大量数据时可能会影响性能。ArrayDeque也实现了Queue接口,它是基于数组实现的双端队列,它其中不能存储空值。ArrayDeque在添加或删除元素时具有很高的性能,因为它支持队列和栈的操作。
使用Queue接口和其实现类非常简单。首先,需要创建一个实例。例如,要创建一个LinkedList实例,可以使用以下代码:
Queue<String> queue = new LinkedList<>();
然后,可以使用Queue接口定义的方法来添加、删除和检查元素。例如,要向队列中添加一个元素,可以使用以下代码:
queue.offer("重庆");
要从队列中删除一个元素和检查队列是否为空:要,请使用以下代码:
String el = queue.poll();
5,Map接口及实现类
Map接口是Java中的一种集合类型,用于存储键值对。它是一个抽象的接口,定义了一系列操作方法,例如添加、删除、查找、遍历等。
Map接口的常用实现类包括:
1. HashMap
2. TreeMap
3. Hashtable
常用方法有:
1. put(key, value):将键值对(key, value)插入到map中,如果key已经存在,则会覆盖之前的value值。
2. get(key):返回指定key对应的value值,如果key不存在,则返回null。
3. remove(key):删除指定key对应的键值对,并返回删除的value值,如果key不存在,则返回null。
4. containsKey(key):判断指定key是否存在于map中,存在返回true,否则返回false。
5. containsValue(value):判断指定value是否存在于map中,存在返回true,否则返回false。
6. size():返回map中键值对的个数。
7. clear():删除map中所有的键值对。
8. keySet():返回map中所有的key组成的set集合。
9. values():返回map中所有的value组成的collection集合。
10.isEmpty():返回映射是否为空。
11.putAll(Map<? extends K,? entends V> map):将参数map中的所有”键/值“添加到映射中。
等不同的方法。