1.集合:
1.1相比数组的优势:
a.可以存储任意类型的对象数据,数组只能存储一种类型的变量
b.集合的长度会发生变化,数组不会
1.2集合概述
----|Collection: 单列集合
-----------|List: 有存储顺序, 可重复
-----------|ArrayList: 数组实现, 查找快, 增删慢
由于是数组实现, 在增和删的时候会牵扯到数组
增容, 以及拷贝元素. 所以慢。数组是可以直接
按索引查找, 所以查找时较快
-----------|LinkedList: 链表实现, 增删快, 查找慢
由于链表实现, 增加时只要让前一个元素记住自
己就可以, 删除时让前一个元素记住后一个元
素, 后一个元素记住前一个元素. 这样的增删效
率较高但查询时需要一个一个的遍历, 所以效率
较低
同样实现了Queue接口,就能用到类似于队列的方法了
1:栈 (1.6) : 主要是用于实现堆栈数据结构的存储方式。
先进后出
push()
pop()
2:队列(双端队列1.5): 主要是为了让你们可以使用LinkedList模拟队列数据结构的存储方式。
先进先出
offer()
poll()
-----------|Vector: 和ArrayList原理相同, 但线程安全, 效率略低
和ArrayList实现方式相同, 但考虑了线程安全问
题, 所以效率略低
-----------|Set: 无存储顺序, 不可重复
-----------|HashSet
-----------|TreeSet
-----------|LinkedHashSet
-----------| Map: 键值对
-----------|HashMap
-----------|TreeMap
-----------|HashTable
-----------|LinkedHashMap
为什么出现这么多集合容器,因为每一个容器对数据的存储方式不同,这种存储方式称之为数据结构(data structure)
注意 集合和数组中存放的都是对象的引用。
有序: 集合的有序不是指自然顺序,而是指添加进去的顺序与元素出来的顺序是一致的。
1.3什么时候用什么类型的集合
Collection |
我们需要保存若干个对象的时候使用集合。 |
List |
如果我们需要保留存储顺序, 并且保留重复元素, 使用List. 如果查询较多, 那么使用ArrayList 如果存取较多, 那么使用LinkedList 如果需要线程安全, 那么使用Vector |
Set |
如果我们不需要保留存储顺序, 并且需要去掉重复元素, 使用Set. 如果我们需要将元素排序, 那么使用TreeSet 如果我们不需要排序, 使用HashSet, HashSet比 TreeSet效率高. 如果我们需要保留存储顺序, 又要过滤重复元素, 那么使用LinkedHashSet |
1.5Collection接口中的共性方法:
a. 增加
add(E e) 添加成功返回true,添加 失败返回false.
addAll(Collection c) 把一个集合 的元素添加到另外一个集合中去。
b. 删除
clear()
remove(Object o)
removeAll(Collection c)
retainAll(Collection c)
c. 查看
size()
d. 判断
isEmpty()
contains(Object o)
containsAll(Collection<?> c)
e. 迭代
toArray()
iterator()
2.List接口中特有方法:
操作的方法都含有index
a.添加
add(int index, E element)
addAll(int index, Collection<? extends E> c)
b.获取:
get(int index)
indexOf(Object o)
lastIndexOf(Object o)
subList(int fromIndex, int toIndex)
c.修改:
set(int index, E element)
d.迭代
listIterator()
增加
public static void main(String[] args) { Collection list = new ArrayList(); // 增加:add() 将指定对象存储到容器中 list.add("计算机网络"); list.add("现代操作系统"); list.add("java编程思想"); System.out.println(list); // [计算机网络, 现代操作系统, java编程思想] // 增加2 将list容器元素添加到list2容器中 Collection list2 = new ArrayList(); list2.add("java核心技术"); list2.addAll(list); list2.add("java语言程序设计"); System.out.println(list2); // [java核心技术, 计算机网络, 现代操作系统, java编程思想, java语言程序设计] }
3.List集合迭代器listIterator
我的理解:这就是List集合的一个指针集合对象,可以对集合通过指针方式对集合操作;
定义:提供了一些方法专门处理集合中的元素.例如删除和获取集合中的元素.该对象就叫做迭代器(Iterator)
特有的方法:hasPrevious()
Previous();
next();add(E e);set(E e)
代码:
public class Demo3 { public static void main(String[] args) { List list = new ArrayList(); list.add("狗娃"); list.add("狗剩"); list.add("铁蛋"); list.add("美美"); ListIterator it = list.listIterator(); //返回的是一个List接口中特有的迭代器 /*System.out.println("有上一个元素吗?"+ it.hasPrevious()); System.out.println("获取上一个元素:"+it.previous()); it.next(); System.out.println("获取上一个元素:"+ it.previous()); while(it.hasNext()){ it.next(); } while(it.hasPrevious()){ System.out.println("元素:"+ it.previous()); } it.next(); it.next(); it.add("张三"); */ it.next(); it.next(); it.set("张三"); System.out.println("集合的元素:"+ list); } }
使用三种方式遍历集合的元素.
第一种: 使用get方法遍历。
第二种: 使用迭代器正序遍历。
第三种: 使用迭代器逆序遍历。
public class Demo4 { public static void main(String[] args) { List list = new ArrayList(); list.add("张三"); list.add("李四"); list.add("王五"); System.out.println("======get方法遍历======="); for(int i = 0 ; i<list.size() ; i++){ System.out.print(list.get(i)+","); } System.out.println(" ======使用迭代器正序遍历=========="); ListIterator it = list.listIterator(); //获取到迭代器 while(it.hasNext()){ System.out.print(it.next()+","); } System.out.println(" ======使用迭代器逆序遍历=========="); while(it.hasPrevious()){ System.out.print(it.previous()+","); } } }
4.
4.线程间通讯(生产者消费者)
(一)一个线程完成自己的任务,要通知另一个线程去完成另一个任务
(二)wait(): 等待 如果线程执行了wait方法,那么该线程会进入等待的状态,等待状态下的线程必须要被其他线程调用notify方法才能唤醒。
notify(): 唤醒 唤醒线程池等待线程其中的一个。
notifyAll() : 唤醒线程池所有等待 线程。
wait与notify方法要注意的事项:
1. wait方法与notify方法是属于Object对象 的。
2. wait方法与notify方法必须要在同步代码块或者是同步函数中才能 使用。
3. wait方法与notify方法必需要由锁对象调用。
(三)例子:生产者消费者
很好的一段代码,解析已经很清楚了关系生产者消费者,synchronized,nodify,wait的使用,线程安全的解决
package cn.itcast.thread; /* 线程通讯: 一个线程完成了自己的任务时,要通知另外一个线程去完成另外一个任务. 生产者与消费者 wait(): 等待 如果线程执行了wait方法,那么该线程会进入等待的状态,等待状态下的线程必须要被其他线程调用notify方法才能唤醒。 notify(): 唤醒 唤醒线程池等待线程其中的一个。 notifyAll() : 唤醒线程池所有等待 线程。 wait与notify方法要注意的事项: 1. wait方法与notify方法是属于Object对象 的。 2. wait方法与notify方法必须要在同步代码块或者是同步函数中才能 使用。 3. wait方法与notify方法必需要由锁对象调用。 问题一:出现了线程安全问题。 价格错乱了... */ //产品类 class Product{ String name; //名字 double price; //价格 boolean flag = false; //产品是否生产完毕的标识,默认情况是没有生产完成。 } //生产者 class Producer extends Thread{ Product p ; //产品 public Producer(Product p) { this.p = p ; } @Override public void run() { int i = 0 ; while(true){ synchronized (p) { if(p.flag==false){ if(i%2==0){ p.name = "苹果"; p.price = 6.5; }else{ p.name="香蕉"; p.price = 2.0; } System.out.println("生产者生产出了:"+ p.name+" 价格是:"+ p.price); p.flag = true; i++; p.notifyAll(); //唤醒消费者去消费 }else{ //已经生产 完毕,等待消费者先去消费 try { p.wait(); //生产者等待 } catch (InterruptedException e) { e.printStackTrace(); } } } } } } //消费者 class Customer extends Thread{ Product p; public Customer(Product p) { this.p = p; } @Override public void run() { while(true){ synchronized (p) { if(p.flag==true){ //产品已经生产完毕 System.out.println("消费者消费了"+p.name+" 价格:"+ p.price); p.flag = false; p.notifyAll(); // 唤醒生产者去生产 }else{ //产品还没有生产,应该 等待生产者先生产。 try { p.wait(); //消费者也等待了... } catch (InterruptedException e) { e.printStackTrace(); } } } } } } public class Demo5 { public static void main(String[] args) { Product p = new Product(); //产品 //创建生产对象 Producer producer = new Producer(p); //创建消费者 Customer customer = new Customer(p); //调用start方法开启线程 producer.start(); customer.start(); } }