JavaSE学习笔记 Day18
个人整理非商业用途,欢迎探讨与指正!!
« 上一篇
文章目录
···
16.2.2迭代器
反复反馈的过程,通常就是为了获取结果使用的。迭代和遍历是类似的
每次迭代都是重复的过程,每次迭代的结果作为下一次的初始值
迭代器是传统的遍历方式,JDK1.5之前使用
迭代器的方法
hasNext:判断迭代器是否有下一个元素
next:获取当前游标对应的元素,将游标向后移动一位
remove:移除当前迭代器中的数据
public class Demo02 {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("hello");
coll.add(new Integer(10));
coll.add(20);
coll.add("bmh");
// 可以通过集合获取迭代器
// 迭代器可以帮我们进行集合的遍历(JDK1.5之前)
Iterator iterator = coll.iterator();
// 判断当前是否有元素
while(iterator.hasNext()) {
// 获取当前,向后移位
System.out.println(iterator.next());
}
}
}
迭代器的常见问题:
1.迭代器是一个一次性的工具,迭代完成之后,游标会停到最后一位,就不能在向下了,迭代器空了没有数据了
2.迭代时每次循环不能调用多次next(),若想调用多次,数据是next()的倍数,否则抛出NoSuchElementException
3.迭代时不要向集合中添加或者删除元素,会抛出ConcurrentModificationException(并发修改异常)
public class Demo02 {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("hello");
coll.add(new Integer(10));
coll.add(20);
coll.add("bmh");
coll.add("bmh");
// 可以通过集合获取迭代器
// 迭代器可以帮我们进行集合的遍历(JDK1.5之前)
Iterator iterator = coll.iterator();
// 判断当前是否有元素
/*while(iterator.hasNext()) {
// 获取当前,向后移位
System.out.println(iterator.next());
}*/
System.out.println("------------------------");
// 第二次迭代
/*while(iterator.hasNext()) {
System.out.println(iterator.next());
}*/
System.out.println("------------------------");
/*while(iterator.hasNext()) {
// 获取当前,向后移位
System.out.println(iterator.next());
System.out.println(iterator.next());
System.out.println("=======");
}*/
System.out.println("------------------------");
while(iterator.hasNext()) {
// 向集合中添加元素
coll.add("hi");
// 获取当前,向后移位
System.out.println(iterator.next());
}
}
}
16.2.3泛型的基本使用
Java中的菱形语法:<>
JDK1.5后引入
参数化类型,可以擦除数据类型,消除向下造型
集合都是泛型类或者泛型接口
public class Demo03 {
public static void main(String[] args) {
// 泛型写Object及其任意的子类(基本类型不能写)
// 前后的类型需要一致,或者前写后不写,默认和前是一致的
// Collection<Integer> coll = new ArrayList<Integer>();
// 泛型添加之后,规范化了类型,如下:当前的集合中只能添加Integer类型
Collection<Integer> coll = new ArrayList<>();
// 规定好了类型
// coll.add("hello");
coll.add(10);
coll.add(20);
// 集合都是泛型类或者接口 Iterator迭代器也是集合
Iterator<Integer> iterator = coll.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
Collection<String> coll1 = new ArrayList<>();
coll1.add("helloworld");
coll1.add(new String("你好世界"));
Iterator<String> it = coll1.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
16.3常见的单列集合实现类
16.3.1ArrayList
List接口的实现类
底层使用数组完成
常用方法:
add(int index, E element) 向集合指定下标中添加元素
add(E e) 在集合的尾部添加元素
get(int index) 通过下标返回指定位置的元素
set(int index, E element) 设置修改,修改的指定下标的内容
listIterator() 获取list专属迭代器
subList(int fromIndex, int toIndex) 集合的截取,从fromIndex到toIndex(不包含)结束
public class Demo04 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
// 添加
list.add("张三");
list.add("李四");
list.add("王五");
// toString是重写过的
System.out.println(list.toString());
// 在指定位置进行添加元素
list.add(0, "赵六");
System.out.println(list);
// 下标需要在范围之内
// list.add(-1,"小七");
// list中可以添加null值
list.add(null);
System.out.println(list);
// 清空
/*list.clear();
System.out.println(list);*/
// 返回下标
System.out.println(list.indexOf("张三"));
System.out.println(list.indexOf(null));
// 是否包含
System.out.println(list.contains("李四"));
// 通过下标移除 返回结果为刚刚被删除的数据
System.out.println(list.remove(0));
System.out.println(list);
// 修改集合的内容 返回的是原本的值
System.out.println(list.set(0, "wch"));
System.out.println(list);
// 获取方法
System.out.println(list.get(0));
// 集合的截取
List<String> subList = list.subList(0, 2);//返回值是List的一个实现类型中的内部类(继承了AbstractList的)
System.out.println(subList);
}
}
16.3.2List集合的遍历
有三种方式
1.迭代器
2.foreach循环
3.for循环(只能遍历list集合)
public class Demo05 {
// list集合的遍历
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("张三");
list.add("李四");
list.add("王五");
// 1.迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
ListIterator<String> it1 = list.listIterator();
// 向下:下面是否有内容
while(it1.hasNext()) {
System.out.println(it1.next());
}
System.out.println("+++++++++++++++++++++++++");
// 向上:上面是否有内容
while(it1.hasPrevious()) {
System.out.println(it1.previous());
}
System.out.println("-------------------------");
// 2.foreach
for (String string : list) {
System.out.println(string);
}
System.out.println("-------------------------");
// 3.普通for循环
for(int i = 0;i<list.size();i++) {
System.out.println(list.get(i));
}
}
}
16.3.3ArrayList的底层实现
ArrayList的底层是数组实现的,所有它有一些数组的特征(下标)
数组结构的特点:1.查询快,2.增删慢
add(E e)方法:
1.若为一次添加元素,那么将底层的空数组进行扩容默认是10,默认的容器可以手动的指定(调用的ArrayList的带参构造)
2.若不为第一次添加元素,当有效个数为size+1,大于数组(底层默认的数组)的长度了就需要扩容
3.每次的扩容为原来的1.5倍(oldCapacity + (oldCapacity >> 1))
ps:移位运算符,是最快速的运算符
①a>>b 等价与 a / 2的b次方
②a<<b 等价与 a * 2的b次方
add(int index,E e)方法:
1.检测下标的范围是否合法
2.判断是否需要扩容
3.将原数组的index下标位向后拷贝
4.在index下标位添加新元素e
5.有效个数++
get(int index)方法:
1.判断下标是否合法
2.返回指定位置的元素
…
16.3.4LinkedList
api和ArrayList类似,有自己独特的添加首尾的方法
底层使用的双链表实现的
public class Demo06 {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
// 方法 默认是添加到最后的
list.add("张三");
list.add("李四");
list.add("王五");
System.out.println(list);
// 添加到结尾
list.addLast("赵六");
System.out.println(list);
// 添加到头部
list.addFirst("李二");
System.out.println(list);
// 获取头和尾
System.out.println(list.getFirst());
System.out.println(list.getLast());
// 和ArrayList类似的方法
System.out.println(list.get(3));
}
}
可以模拟栈和队列的数据结构
栈:先进后出
队列:先进先出
public class Demo07 {
public static void main(String[] args) {
// 模拟栈
LinkedList<String> list = new LinkedList<>();
// 入栈:先进后出
// 调用addFirst
list.push("张三");//先进入的存在最后
list.push("李四");
list.push("王五");
list.push("赵六");
System.out.println(list.get(0));
System.out.println(list);
// 出栈:将数据移除
list.pop();//赵六出栈
list.pop();//王五出栈
list.pop();//李四出栈
list.pop();//张三出栈
System.out.println(list);
System.out.println("--------------------------------");
// 模拟队列
// 调用add(默认添加到尾部)
list = new LinkedList<>();
list.offer("张三");
list.offer("李四");
list.offer("王五");
list.offer("赵六");
System.out.println(list);
// 出列
list.poll();//张三
list.poll();//李四
list.poll();//王五
list.poll();//赵六
System.out.println(list);
}
}
16.3.5LinkedList底层实现
底层选用双链表结构
数据结构中存在表结构
顺序表:内存空间是连续的,数组,允许随机访问,尾插和尾删方便,优点:查询快;缺点:插入的效率低,删除效率低,长度固定(查快,删改慢)
单链表:内存不是连续的,可以随意的增删改,查询效率低,应用:HashSet,HashMap
单链表只能下一个
双链表:和单链表类似,内存不连续,查询效率比单链表快一倍,但查询效率仍然是低的,应用:LinkedList
双链表可以下一个,也可以上一个
//LinkedList双链表的源码
private static class Node<E> {
E item;//当前元素
Node<E> next;//下一个元素
Node<E> prev;//上一个元素
//构造方法
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
16.3.6Vector
与ArrayList方法基本一样
底层同样使用的是数组
Vector是线程安全的,底层中只要有synchronized关键字就是线程安全的
线程安全都是效率低
创建时底层数据的默认长度为10
和ArrayList有一定的区别,默认长度是0,第一次添加数据时才会扩容到10
查询快,在不考虑线程安全时使用ArrayList,考虑时使用Vector
public class Demo08 {
public static void main(String[] args) {
Vector<String> v = new Vector<>();
v.add("张三");
v.add("李四");
System.out.println(v);
v.remove("张三");
System.out.println(v);
// 通过下标移除
v.remove(0);
System.out.println(v);
v.remove("");
}
}
16.3.7HashSet
Set集合的主要实现类之一
特点:无序(插入无序),无下标,不可重复,只能添加一个null值
常用的方法和Collection接口中基本一致
public class Demo09 {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("张三");
set.add("李四");
set.add("王五");
// 取出顺序和添加顺序无关:无序
System.out.println(set);
// 没有下标
// set.get(0);
// 不可重复
set.add("张三");
System.out.println(set);
// 可以添加null值,但是只能加入一个
set.add(null);
set.add(null);
System.out.println(set);
}
}
16.3.8HashSet数值的存放
无序:只是添加和set集合的存放是不一样的
在存储时内部是有一套自己的方案的,按照hash值进行存放的
public class Demo10 {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
// 0~9的hash值是连续的
// 无序并不是杂乱无章的,只是添加和存储的顺序不一样
set.add("1");
set.add("7");
set.add("2");
set.add("3");
set.add("4");
set.add("8");
set.add("0");
set.add("5");
set.add("9");
set.add("6");
System.out.println(set);
}
}