Collection
遍历
- 普通for循环
- 增强for循环
- iterator
泛型
ArrayList<E>
使用时确定E的类型,确定集合中存放的datatype。编译时检查出来,存引用的datatype。
不使用泛型:什么引用类型都可以添加。
public class Test01 {
//这是main方法,程序的入口
public static void main(String[] args) {
//创建一个ArrayList集合,向这个集合中存入学生的成绩:
ArrayList al = new ArrayList();
al.add(98);
al.add(18);
al.add(39);
al.add(60);
al.add(83);
al.add("丽丽");
//对集合遍历查看:
for(Object obj:al){
System.out.println(obj);
}
}
}
使用泛型,编译期进行检查
public static void main(String[] args) {
//创建一个ArrayList集合,向这个集合中存入学生的成绩:
// 加入泛型的优点:在编译时期就会对类型进行检查,不是泛型对应的类型就不可以添加入这个集合。
ArrayList<Integer> al = new ArrayList<Integer>();
al.add(98);
al.add(18);
al.add(39);
al.add(60);
al.add(83);
/*al.add("丽丽"); al.add(9.8);*/
//对集合遍历查看:
/*for(Object obj:al){
System.out.println(obj);
}*/
for(Integer i:al){
System.out.println(i);
}
}
- 自定义泛型
泛型类
ClassName<A>
相当于占位。但是现在确定的是这个类型一定是一个引用数据类型,而不是基本数据类型
public class GenericTest<E> {
int age;
String name;
E sex;
public void a(E n){
}
public void b(E[] m){
}
}
class Test{
//这是main方法,程序的入口
public static void main(String[] args) {
//GenericTest进行实例化:
// (1)实例化的时候不指定泛型:如果实例化的时候不明确的指定类的泛型,那么认为此泛型为Object类型
GenericTest gt1 = new GenericTest();
gt1.a("abc");
gt1.a(17);
gt1.a(9.8);
gt1.b(new String[]{"a","b","c"});
//(2)实例化的时候指定泛型:---》推荐方式
GenericTest<String> gt2 = new GenericTest<>();
gt2.sex = "男";
gt2.a("abc");
gt2.b(new String[]{"a","b","c"});
}
}
继承
ClassName2 extends GenetricName1<Integer>
应用场合
细节:
泛型类可以定义多个参数类型:
静态方法不能使用泛型。
不能用E[]
创建。
泛型方法
要求:
(1)这个方法的泛型的参数类型要和当前的类的泛型无关
(2)前面加上<T>
,否则会把T当成一种数据类型
(3)T类型在调用方法时确定。
(4)可以是静态方法。
// 不是
public static void a(E e){}
// 是
public static <T> void a(T e){}
// E和类的泛型一样,不是
public <E> void a(E e){}
泛参继承
子类A,父类B。G<A>
和G<B>
无继承关系。仅编译器写代码时限制。
- 通配符
因为泛型参数无法重载,因此需要使用通配符。
// 报错
public void a(List<String> list){}
public void a(List<Integer> list){}
使用G<?>
即可,其是G<A>,G<B>
的父类。
public void a(List<?> list){
//内部遍历的时候用Object即可,不用?
for(Object a:list){
System.out.println(a);
}
}
细节
不可随意写入数据,只能写入null。
list.add("abc"); // 报错
list.add(null);
Object s = list.get(0); // 读取
- 泛型受限
// 开始使用泛型受限:泛型的上限
List<? extends Person>:
// 就相当于:
List<? extends Person>是List<Person>的父类,是List<Person的子类>的父类
// 开始使用泛型受限:泛型的下限
List<? super Person>:
// 就相当于:
List<? super Person>是List<Person>的父类,是List<Person的父类>的父类
List接口
- ArrayList1.7
(1)1.5倍扩容,初始为10
(2)底层使用elementData
- ArrayList1.8
(1)1.5倍扩容,初始为0。首次add时,扩容为10,节省内存。
(2)依旧使用Object类型数组。 - Vector
(1)2倍扩容。
(2)线程安全。synchronize add - LinkedList
(1)添加元素:add有异常;offer无异常。
(2)弹出元素:remove有异常,poll无异常
迭代器
hasNext(), next()
增强for循环底层是通过迭代器实现。
ListIterator迭代器
原iter和集合操作不可同时进行。通过ListIterator,迭代和添加都是靠一个ListIterator来完成。
// 报错
Iterator<String> it = list.iterator();
while(it.hastNext()){
if ("cc".equals(it.next()){
list.add("kk");
}
}
补充:比较器使用
- 比较String
a.compareTo(b);
- 比较double
((Double) a).compareTo((Double) b);
- 自定义数据类型
(1)内部比较器:实现compareTo
方法。
(2)外部比较器:实现Comparator<XX>
类。多态,扩展性好。
Set
唯一,无序。
遍历:增强for,iterator。
- HashSet
底层是HashMap - LinkedHashSet
在HashSet基础上多了一个总的链表,将放入的元素串在一起,方便有序遍历。 - TreeSet
唯一,输入顺序不保留,数值上升序。底层二叉树。
树中存放自定义类型需要实现比较器,一般用外部比较器。
Map
- Hashtable
低效,线程安全,不可存null - TreeMap
唯一,数值有序,需要实现比较器(外部)。 - LinkedHashMap
hash+list,按输入顺序输出。 - HashMap
无序,唯一。可存null(也唯一),线程不安全。
2倍扩容,初始16,装填因子0.75.
设置2倍扩容的好处
(1)h&(len-1)<=>h%len
,计算位置快捷,取模效率低。等效的前提是2倍扩容。
(2)防止hash位置冲突。不是2的整数倍,哈希冲突概率高。
Collections工具类
(1)不支持创建对象。因为构造器私有化了。
(2)里面的属性和方法都被static修饰,可以直接用Collections.method()
调用。
常用方法
(1)addAll
(2)binarySearch&sort
(3)copy
(4)fill填充
Stack
是Vector的子类,add返回True,push返回插入的值。
同步类容器
把ArrayList, HashMap等变成线程安全的:
List list = Collections.synchronizedList(new ArrayList());
原理:mutex+synchronized
ConcurrentMap并发容器
(1)ConcurrentHashMap代替HashMap, HashTable。
分出16个片区,单独加锁,性能高。
(2)ConcurrentSkipListMap代替TreeMap。
COW并发容器
写时复制,读写分离。
复制旧容器到新容器,再添加元素,换指针。
(1)CopyOnWriteArrayList
(2)CopyOnWriteArraySet
调用add,每次调用addIfAbsent遍历数组,性能低于CopyOnWriteArrayList。
队列
阻塞队列
BlockingQueue继承Queue,Queue继承自Collection
添加:
add(E e)
无空间抛异常IllegalStateException。offer(E e)
无空间返回false。put(E e)
无空间则阻塞
查询:
take()
获取并移除头部,可用前阻塞。poll(long timeout, TimeUnit unit)
获取并移除头部,可用前指定时间前阻塞。
删除:
remove(Object o)
移除指定
阻塞队列常见子类
- ArryaBlockingQueue
(1)不可同时读写,同一把锁。
(2)不可添加null。
(3)得到头元素不删除:peek
(4)notFull¬Empty是两个队列。
-
LinkedBlockingQueue
(1)可同时读写,两把锁。
(2)可选择有边界(指定长度的话)。此时put&take可阻塞。
(3)count&getAndIncrement() -
SynchronousQueue
先取才能加元素,队列没有容量。
意义:提高方便高效的进行线程间数据的传送。效率极高,不会产生队列数据争抢问题。
取出元素 不能用peek,因为peek不会将元素从队列中拿走,只是查看的效果; -
PriorityBlockingQueue
(1)无界,默认初始11.
(2)不可放null。
(3)不可放入不可比较的对象。会抛ClassCastException。
(4)取元素时,以CompareTo优先级传出。 -
DelayQueue
无界,用于放置实现了Delayed接口的对象,其中的对象只能在到期时才被拿走。
元素必须实现了Comparable。重写getDelay和compareTo。
用处:
(1)淘宝订单业务:下单之后如果三十分钟之内没有付款就自动取消订单。
(2)饿了吗订餐通知:下单成功后60s之后给用户发送短信通知。
(3)关闭空闲连接。服务器中,有很多客户端的连接,空闲一段时间之后需要关闭之。
(4)缓存。缓存中的对象,超过了空闲时间,需要从缓存中移出。
(5)任务超时处理。在网络协议滑动窗口请求应答式交互时,处理超时未响应的请求等。
双端队列Deque
两头都可存取。
实现类:LinkedList