util包主要提供了集合、日历和随机数的工具包。
集合的两个super接口collection和map
public interface Collection<E> extends Iterable<E> {
Collection 的子接口:List、Set、Queue接口
public interface List<E> extends Collection<E> {
List接口对Collection进行了简单的扩充,它的具体实现类常用的有ArrayList和LinkedList。你可以将任何东西放到一个List容器中,并在需要时从中取出。ArrayList从其命名中可以看出它是一种类似数组的形式进行存储,因此它的随机访问速度极快,而LinkedList的内部实现是链表,它适合于在链表中间需要频繁进行插入和删除操作。在具体应用时可以根据需要自由选择。前面说的Iterator只能对容器进行向前遍历,而ListIterator则继承了Iterator的思想,并提供了对List进行双向遍历的方法。参考链接
常用实现类:
ArrayList、LinkList、Vector 三个类
ArrayList:快速访问使用-动态数组
LinkedList:增加删除适用-链表
Vector:线程安全使用
特点
List方法
List list = new ArrayList(); //声明list
list.add("aa"); //向列表尾部插入指定元素
list.add(1, "bb"); //向列表指定位置插入指定元素,索引从0开始
list.addAll(new ArrayList()); //追加指定 collection中的所有元素到此列表的结尾
list.clear(); //从list中移除所有元素
list。contains("cc"); //若list包含指定元素返回true
list.equals(new ArrayList()); // 比较指定的对象与列表是否相等
list.get(0); // 返回列表中指定位置的元素
list.toArray(); // 返回以正确顺序包含列表中的所有元素的数组
list.indexOf("aa"); // 返回列表中首次出现指定元素的索引,如果列表不包含此元素,则返回 -1
list.lastIndexOf("dd"); // 返回列表中最后出现指定元素的索引,如果列表不包含此元素,则返回 -1
list.isEmpty(); // 如果列表不包含元素,则返回 true
list.remove(0); // 移除列表中指定位置的元素
list.remove("lwc"); // 移除列表中出现的首个指定元素
list.removeAll(new ArrayList()); // 从列表中移除指定 collection中包含的所有元素
list.set(0, "lp"); // 用指定元素替换列表中指定位置的元素
list.size(); // 返回列表中的元素数
list.subList(1, 2); // 返回列表中指定的fromIndex(包括)和toIndex(不包括)之间的部分视图
list.hashCode(); // 返回列表的哈希码值
list.toArray(new String[] {
"a", "b" }); // 返回以正确顺序包含列表中所有元素的数组
public interface Set<E> extends Collection<E> {
Set接口也是Collection的一种扩展,而与List不同的时,在Set中的对象元素不能重复,也就是说你不能把同样的东西两次放入同一个Set容器中。它的常用具体实现有HashSet和TreeSet类。HashSet能快速定位一个元素,但是你放到HashSet中的对象需要实现hashCode()方法,它使用了前面说过的哈希码的算法。而TreeSet则将放入其中的元素按序存放,这就要求你放入其中的对象是可排序的,这就用到了集合框架提供的另外两个实用类Comparable和Comparator。一个类是可排序的,它就应该实现Comparable接口。有时多个类具有相同的排序算法,那就不需要在每分别重复定义相同的排序算法,只要实现Comparator接口即可。集合框架中还有两个很实用的公用类:Collections和Arrays。Collections提供了对一个Collection容器进行诸如排序、复制、查找和填充等一些非常有用的方法,Arrays则是对一个数组进行类似的操作。
实现类
HashSet、TreeSet
HashSet:快速访问使用-哈希表-
TreeSet:排序使用-红黑树
特点
List和Set的区别
public interface Queue<E> extends Collection<E> {
队列,先进先出
Queue用于模拟"队列"这种数据结构(先进先出 FIFO)。队列的头部保存着队列中存放时间最长的元素,队列的尾部保存着队列中存放时间最短的元素。新元素插入(offer)到队列的尾部,访问元素(poll)操作会返回队列头部的元素,队列不允许随机访问队列中的元素。
E poll();//出队
public interface Map<K,V> {
Map是一种把键对象和值对象进行关联的容器,而一个值对象又可以是一个Map,依次类推,这样就可形成一个多级映射。对于键对象来说,像Set一样,一个Map容器中的键对象不允许重复,这是为了保持查找结果的一致性;如果有两个键对象一样,那你想得到那个键对象所对应的值对象时就有问题了,可能你得到的并不是你想的那个值对象,结果会造成混乱,所以键的唯一性很重要,也是符合集合的性质的。当然在使用过程中,某个键所对应的值对象可能会发生变化,这时会按照最后一次修改的值对象与键对应。对于值对象则没有唯一性的要求。你可以将任意多个键都映射到一个值对象上,这不会发生任何问题(不过对你的使用却可能会造成不便,你不知道你得到的到底是那一个键所对应的值对象)。Map有两种比较常用的实现:HashMap和TreeMap。HashMap也用到了哈希码的算法,以便快速查找一个键,TreeMap则是对键按序存放,因此它便有一些扩展的方法,比如firstKey(),lastKey()等,你还可以从TreeMap中指定一个范围以取得其子Map。键和值的关联很简单,用pub(Object key,Object value)方法即可将一个键与一个值对象相关联。用get(Object key)可得到与此key对象所对应的值对象。
常见实现类
HashMap、TreeMap、Hashtable
特点
补充:java是先实现了Map,然后通过包装了一个所有value都为null的Map就实现了Set集合,我们也可以从Set的构造方法中看出来
public HashSet() {
map = new HashMap<>();
}
判断键是否相同的步骤:
方法
1、put/putAll/remove/clear 增加删除 get/values 获取值
2、containKey/containValue 判断
3、entrySet/keySet 获取迭代
4、equals/hashcode 比较
Iterator是遍历集合的根本方法,虽然有Iterable但是,其中依然把遍历的工作交给了Iterator来做,只是增加了forEach遍历
public interface Iterator<E> {
主要方法
这个是一个空接口,个人感觉是很奇怪,要实现clone这个方法拷贝对象,必须要实现Clonable这个接口,然后重写Object类的clone方法,不然就报CloneNotSupportedException。
public interface Cloneable {
}
作用:
而反序列化则相反,就是把持久化的字节文件数据恢复为对象的过程。
例子:
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String userId;
private String userName;
public Person(String userId, String userName) {
this.userId = userId;
this.userName = userName;
}
@Override
public String toString() {
return "Person{" +
"userId='" + userId + '\'' +
", userName='" + userName + '\'' +
'}';
}
}
public class SerializableTest {
/**
* 序列化写
* 文件内容:��srcom.citicbank.PersonLuserIdtLjava/lang/String;LuserNameq~xpt1001tchenxinsheng
*/
public static void writeObj() {
Person person= new Person("1001", "chenxinsheng");
try {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("/Users/chenxinsheng/java/sourcescode/user.txt"));
objectOutputStream.writeObject(person);
objectOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 序列化读
* 输出Person{userId='1001', userName='chenxinsheng'}
*/
public static void readObj() {
try {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("/Users/chenxinsheng/java/sourcescode/user.txt"));
try {
Object object = objectInputStream.readObject();
Person person = (Person) object;
System.out.println(person);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
writeObj();
readObj();
}
}
public interface Serializable {
}
主要学习集合的实现类、日期、随机数、扫描器类
ArrayList是List的实现类,是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
// 默认初始的容量
private static final int DEFAULT_CAPACITY = 10;
// 数组最大长度
private static final int MAX_ARRAY_SIZE = 2147483639;
// 当前数组长度
private int size;
// 一个空对象,如果使用默认构造函数创建,则默认对象内容默认是该值
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
ArrayList构造方法
提供了三个构造方法,无参、带容量、带集合三种
无参构造函数
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
具体例子:
List list=new ArrayList();
//无参构造函数创建对象
//默认容量是0
带容量的构造函数
public ArrayList(int initialCapacity) {
具体例子
List list=new ArrayList(20);
//20是容量
传入参数如果是大于等于0,则使用用户的参数初始化,如果用户传入的参数小于0,则抛出异常。
带Collection对象的构造函数
public ArrayList(Collection<? extends E> c) {
具体例子
List list=new ArrayList();
System.out.println(list.size());//输出0
list.add(1);
System.out.println(list.size());//输出1
List<Integer> list1=new ArrayList(list);
System.out.println(list1.size());//输出1
1)将collection对象转换成数组,然后将数组的地址的赋给elementData。
2)更新size的值,同时判断size的大小,如果是size等于0,直接将空对象EMPTY_ELEMENTDATA的地址赋给elementData
3)如果size的值大于0,则执行Arrays.copy方法,把collection对象的内容(可以理解为深拷贝)copy到elementData中。
常用方法就不一一罗列了,别人已经帮我整理好了,接下来的类也不涉及具体方法,最重要的还是理解整个类的框架和构造函数。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList属性
transient int size = 0;//集合大小
transient Node<E> first;//头节点
transient Node<E> last;//尾节点
LinkedList构造方法
提供2个无参和带集合的构造方法
无参构造方法
public LinkedList() {
}
//例子
List list2=new LinkedList();
System.out.println(list2.size());//输出0
带 Collection的构造方法
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
//例子
List list3=new LinkedList(list3);
System.out.println(list3.size());//输出0
迭代器-遍历集合
LinkedList提供了ListIterator,我们也可以直接使用Iterator的迭代器;
List list3=new LinkedList(list);
list3.add("chen");
list3.add("xin");
list3.add("sheng");
ListIterator listIterator=list3.listIterator();
while (listIterator.hasNext()){
System.out.println(listIterator.next());
}
Iterator iterator=list3.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//都输出
chen
xin
sheng
Vector和ArrayList的区别在于,vector多了一个synchronized关键字。
提供了四个
比ArrayList多了一个
public Vector(int initialCapacity, int capacityIncrement) {
//initialCapacity初始容量
//capacityIncrement增量:每次增加容量是多少
例子:
Vector vector=new Vector(1,2);
System.out.println(vector.capacity());//输出1
vector.add("chen");
System.out.println(vector.capacity());//输出1
vector.add("xin");
System.out.println(vector.capacity());//输出3了,超出初始容量后的增量
方法前面多了一个:synchronized
public synchronized void removeElementAt(int index) {
Map的键值对实现类,键不可以重复,是Map的实现类,主要方法是get和put.
HashMap基于散列算法实现,在JDK1.8中引入了红黑树来优化过长的的链表
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
例子:
HashMap hashMap=new HashMap();//无参构造函数
//负载因子默认为0.75
hashMap.put(1,"chen");
hashMap.put(2.0,"xin");
hashMap.put("he","sheng");
System.out.println(hashMap.get(1));//输出chen
无序不重复的集合使用哈希算法实现
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
构造方法:
loadFactor负载因子:
一般我们使用默认的无参构造方法创建对象,但是当我们对时间和空间有要求的时候我们就要考虑负载因子,默认为0.75.参考链接
HashMap hashMap1=new HashMap(3);//初始容量
HashMap hashMap2=new HashMap(2,3);//初始容量和负载因子
HashMap hashMap3=new HashMap(hashMap2);//参数是HashMap
对于 HashMap 来说,负载因子是一个很重要的参数,该参数反应了 HashMap 桶数组的使用情况(假设键值对节点均匀分布在桶数组中)。通过调节负载因子,可使 HashMap 时间和空间复杂度上有不同的表现。当我们调低负载因子时,HashMap 所能容纳的键值对数量变少。扩容时,重新将键值对存储新的桶数组里,键的键之间产生的碰撞会下降,链表长度变短。此时,HashMap 的增删改查等操作的效率将会变高,这里是典型的拿空间换时间。相反,如果增加负载因子(负载因子可以大于1),HashMap 所能容纳的键值对数量变多,空间利用率高,但碰撞率也高。这意味着链表长度变长,效率也随之降低,这种情况是拿时间换空间
threshold = capacity * loadFactor
HashTable也是Map的实现类,看源码就会发现和HashMap基本上是一样的,但是HashTable在很多方法之前多了一个关键字synchronized,所以它是线程安全的。
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {
Dictionary是一个抽象类,里面有Map的公共的抽象方法,但是这个是一个过时的实现方式,新的实现都要实现Map接口。
Hashtable是通过"拉链法"实现的哈希表。它包括几个重要的成员变量:table, count, threshold, loadFactor, modCount。
成员变量
构造方法和HashMap的一样这里就不再赘述了。
内部实现就是一个红黑树
K key;
V value;
Entry<K,V> left;
Entry<K,V> right;
Entry<K,V> parent;
boolean color = BLACK; //black=true//Red=false
TreeMap是SortedMap的实现类,本质上的是TreeMap会对Key值进行按照自然顺序排序,而HashMap没有这样的实现,所有的内容都是无序的。
Map<String, Integer> map = new TreeMap<>();
map.put("chen", 1);
map.put("xin", 2);
map.put("sheng", 3);
for (String key : map.keySet()) {
System.out.println(key);
}
// chen , sheng ,xin 按照 c s x 的字母顺序排序
从TreeMap的构造函数可以看出来。每个都有这样一句话,
comparator = null;
如果在集合中的类型是常见的数值和String、Character基础类型在不需要重写比较方法,但是如果集合中放的是上诉之外的类型,必须实现compare方法。实现的compare方法可以可以使用元素的自然顺序,也可以使用集合中自定义的比较器来进行排序;
例子:
public class Main {
public static void main(String[] args) {
Map<Person, Integer> map = new TreeMap<>(new Comparator<Person>() {
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
});
map.put(new Person("Tom"), 1);
map.put(new Person("Bob"), 2);
map.put(new Person("Lily"), 3);
for (Person key : map.keySet()) {
System.out.println(key);
}
// {Person: Bob}, {Person: Lily}, {Person: Tom}
System.out.println(map.get(new Person("Bob"))); // 2
}
}
class Person {
public String name;
Person(String name) {
this.name = name;
}
public String toString() {
return "{Person: " + name + "}";
}
}
推荐阅读链接:Java集合–TreeMap完全解析
扫描器类,从文件,输入流,字符串中解析出基本类型值和字符串值,常用于读取命令行输入内容。
比如:
Scanner scanner1=new Scanner(System.in);
System.out.println(scanner1.next());
Scanner构造方法:
Scanner scanner1=new Scanner(System.in);//
Scanner scanner2=new Scanner(new File("test.txt"))
Scanner scanner2=new Scanner("sting fsfs ");
这个是我们使用最多的地方了吧。
Scanner常用方法
(1)hasNext() :返回此Scanner当前扫描位置后是否还存在下一个
(2)hasNextLine():检查是否当前Scanner是否存在下一行数据,若存在,则返回True
(3)next():返回下一个数据,nextInt()返回一个整数,同理还有nextShort(),nextLong() //带next这些方法是开始键盘输入的语句
,其中,若nextInt(n),表示nextInt()返回的数字不能大于等于n,否则抛出异常
(4)nextLine():返回下一行数据。nextLine()是返回一整行,next()是返回一个
(5)useDelimiter:改变当前Scanner用于分割字符串的标识符,默认为空格(如:ab cd ef,则会被空格分割为三段数据:ab,cd 和 ef),会 影响next()获取的数据
(6)delimiter():返回当前Scanner的分隔符
定时器类
定时执行某个任务,具体的任务由TimerTask来完成。
void cancel()
终止此计时器,丢弃所有当前已安排的任务。
int purge()
从此计时器的任务队列中移除所有已取消的任务。
void schedule(TimerTask task, Date time)
安排在指定的时间执行指定的任务。
void schedule(TimerTask task, Date firstTime, long period)
安排指定的任务在指定的时间开始进行重复的固定延迟执行。
void schedule(TimerTask task, long delay)
安排在指定延迟后执行指定的任务。
void schedule(TimerTask task, long delay, long period)
安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。
void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
安排指定的任务在指定的时间开始进行重复的固定速率执行。
void scheduleAtFixedRate(TimerTask task, long delay, long period)
安排指定的任务在指定的延迟后开始进行重复的固定速率执行。
boolean cancel()
取消此计时器任务。
abstract void run()
此计时器任务要执行的操作。
long scheduledExecutionTime()
返回此任务最近实际 执行的已安排 执行时间。
例子:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
System.out.println("延迟一秒再执行");
}
}, 1000);//千分之一秒,这里的1000就是一秒