ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

并发修改异常和列表迭代器

2021-01-08 02:02:35  阅读:203  来源: 互联网

标签:String 迭代 al 列表 lit 并发 add 集合


并发修改异常(☆☆)
并发修改异常产生的原因:
"迭代器"在遍历集合的时候 , "集合"对元素进行了增删(改变集合长度)。就会产生并发修改异常:

		并发: 一起,多个东西 同时操作一个内容。 

		解决:(☆☆☆☆)
			删除:删除所有的a元素
				ArrayList<String> al = new ArrayList<>();
				al.add("a");
				al.add("a");
				al.add("a");
				al.add("b");
				al.add("a");
				al.add("a");
				
				解决方案1:集合自己去遍历,不需要你迭代器参与了。 集合自己遍历的时候,集合自己删除。 (这种方式 只针对 List集合, 其他的集合 set Collection 你都用不了)
					1:
						for (int i = 0; i < al.size(); i++) {
							String s = al.get(i);
							if(s.equals("a")){
								al.remove(i);
								i--;
							}
						}
					2:
						for (int i = al.size()-1; i >=0 ; i--) {
							String s = al.get(i);
							if(s.equals("a")){
								al.remove(i);
							}
						}
				解决方案2: 我迭代器遍历集合的时候, 我让迭代器自己去删除元素。
					1:适用与 任何 单列集合
						Iterator<String> iterator = al.iterator();  // 
						while (iterator.hasNext()){
							String next = iterator.next();
							if (next.equals("a")){
								iterator.remove();
							}
						}
					2:适用于 list集合。
						ListIterator<String> lit = al.listIterator(); //
						while (lit.hasNext()){
							String next = lit.next();
							if (next.equals("a")){
								lit.remove();
							}
						}

			增加:看看集合中是否有 b元素, 我添加 一个c元素。( 只针对 List集合, 其他的集合 set Collection 你都用不了)
				解决方案1: 集合自己去遍历,自己去添加
					for (int i = 0; i < al.size(); i++) {  // 这种只适用于List集合。
						String s = al.get(i);
						if(s.equals("b")){
							al.add("c"); // 添加到了集合最后面
						}
					}
				解决方案2: 迭代器 去遍历集合的时候, 让迭代器去添加元素。
					ListIterator<String> lit = al.listIterator();
					while (lit.hasNext()){
						String next = lit.next();
						if (next.equals("b")){
							lit.add("c"); // 添加的是 光标坐在的位置。
						}
					}


列表迭代器 (☆☆☆):
	1: ListIterator listIterator();  是 List 体系 特有的方法。 
	2: Iterator  是 ListIterator 这个接口的 父接口

	细节:
		1: 因为我们如果使用 无参数的 ListIterator listIterator(); 拿到的这个列表迭代器的光标是在最前面的。
			所以必须向后面编译一遍,把光标放到了最后,才能再向前遍历。
			这种方式比较麻烦。
			public class Demo {
				public static void main(String[] args) {
					List<String> list = new ArrayList<>();
					list.add("hello");
					list.add("world");
					list.add("java");

					Iterator<String> it = list.iterator();
					while (it.hasNext()){
						System.out.println(it.next());
						//System.out.println(it.next());
					}
					
					while (it.hasNext()){ // 此处不会进入循环。 因为 上一次的while循环已经把迭代器的指针放到了之后,所以此处判断,已经没有下一个元素了。
						System.out.println(it.next());
					}
				}
			}
			public class Demo1 {
				public static void main(String[] args) {
					ArrayList<String> al = new ArrayList<>();
					al.add("aa");
					al.add("aa1");
					al.add("aa2");
					al.add("aa3");


					ListIterator<String> lit = al.listIterator(); // 你获取的迭代器 ,最开的时候 光标在最前面
					while (lit.hasPrevious()){ //有前一个元素吗?
						System.out.println(lit.previous());
					}  //并不会打印任何东西。

				}
			}
			public class Demo1 {
				public static void main(String[] args) {
					ArrayList<String> al = new ArrayList<>();
					al.add("aa");
					al.add("aa1");
					al.add("aa2");
					al.add("aa3");


					ListIterator<String> lit = al.listIterator(); // 你获取的迭代器 ,最开的时候 光标在最前面

					while (lit.hasNext()){
						System.out.println(lit.next());
					}

					while (lit.hasPrevious()){ 
						System.out.println(lit.previous());
					}  
					/*
					因为 获取迭代器的时候 ,获取的迭代器光标是在最前面,所以 不能直接 向前遍历。
					只能先先后遍历一遍,然后 再向前遍历才可以。
					这样做很麻烦。
					我们就想 如果我们获取的迭代器的时候, 光标就再最后的话,就可以直接向前遍历了啊。
					所有就有了下面的改进。
					*/
					 ListIterator<String> lit = al.listIterator(al.size()); // 获取迭代器的时候 我就想让迭代器的光标放在最后。
					while (lit.hasPrevious()){ 
						System.out.println(lit.previous());
					}

				
				}
			}
		2: ListIterator listIterator(int index);  通过这个方法 就可以拿到光标在指定位置的 列表迭代器。 
			通过这种方式,拿到光标在最后的 列表迭代器, 就可以直接向前遍历了。

增强for循环(☆☆☆☆☆)
jdk1.5的时候 出现的新特性。 他就是为了简化迭代器遍历集合的代码的。 底层依然是用的迭代器。
只要实现了 Iterable 接口的所有的子类对象 都可以被增强for循环操作。
Iter 迭代
able 可以...的
Throw 扔出
able 可以...的 Throwable

格式:
	for (元素的类型 变量 : 集合或者数组 ){    // 冒号后面的东西 必须是 实现了 Iterable接口 ,底层仍是迭代器
		// 变量 就是代表的每个元素
	}

证明:
	1:冒号后面的东西 必须是 实现了 Iterable接口 
	2:增强for循环的底层是用的 迭代器
		class Student implements Iterable<Integer>{
			@Override
			public Iterator<Integer> iterator() {
				return new Itr();
			}

			private class Itr implements Iterator<Integer>{

				@Override
				public boolean hasNext() {
					return true;
				}

				@Override
				public Integer next() {
					return 1;
				}
			}
		}

		Student s = new Student();
		for (Object a:s){
			System.out.println(a);
		}

集合的遍历方式总结:
	Collection : 2种  普通迭代器  增强for循环
		List : 4种  普通迭代器 列表迭代器  普通for循环 增强for循环。
		Set : 2种  普通迭代器  增强for循环

数据结构:
任何的容器 : 不都为了存储数据。
数据在容器当中的排列顺序,存储顺序,和结构。 这些就是数据结构。

栈: 先进后出    类比容器: 弹夹。
队列: 先进先出  类比现实生活中的容器: 水管。 
数组: 查询快 增删慢
链接: 查询慢 增删快。
	单向链表
	双向链表: LinkedList 

List 的子类:
ArrayList :数组: 查询快 增删慢
LinkedList :链接: 查询慢 增删快。(双向链表)
因为他的底层是双向链表,所以他里面有很多的和头尾相关的方法。
addFirst(E e);
addLast(E e);
removeLast();
removeFirst();
getFirst();
getLast();

	链表结构,不像数组那样, 数组可以通过索引获取元素, 链表没有索引,所以链表要想查找元素,只能从头往后 或者从后往前查找。
	
	List 里面 有一个特有方法 get(int index);
		既然List接口有这个方法。
		那么 LinkedList 也是有这个方法的。 那与 链表不能通过索引获取元素 岂不是矛盾吗?
		没有矛盾的:  LinkedList底层 调用此方法的时候,会先判断 你找的这个索引数 比 数组长度的一半 大还小。  如果比一半小
			我就从前往后查找。  如果说比一半大,我就从后往前查找。

Set :不可以存储重复元素 (存取元素无序,没有索引,不能通过普通for循环遍历)
hashCode():
哈希值: 在java中 你看不到真实的物理地址。 jdk的Object中HashCode方法, 会根据对象的真实物理地址,结合哈希算法,给你算出唯一的一个值。
从而让这个值来代替 地址值。

	Object的HashCode方法, 不同的对象的哈希值 是肯定不一样的。  相同对象的哈希值 是一样的。 

	但是我们可以通过重写HashCode方法,使得 不同对象的哈希值 相同。
		比如:
			String类 重写了Object的HashCode方法
				int a = "重地".hashCode();
				int b = "通话".hashCode();
				System.out.println(a==b);//true

				System.out.println("重地"=="通话"); // == 比的是真是的物理地址。 false
				


HashSet :
	底层 是哈希表结构:
	他什么保证元素唯一的呢?
		HashSet 存储元素的时候:                        // //Object的HashCode方法, 不同的对象的哈希值 是肯定不一样的。  相同对象的哈希值 是一样的。hash表依赖于hashcode()和equals()方法 
			首先拿着元素的 HashCode值,和哈希表所有的哈希值去比。看看哈希表中,有没有存在存在和元素的哈希值相同的元素;
				如果不存在 : 就直接把这个元素 添加到哈希表中
				如果存在: 就让这个元素 拿着自己的equals方法,和哈希值相同的那些元素,依次去equals
					如果比了一遍:都是false  则添加到集合中
					如果比了一遍:有返回true的 则不添加集合(替换)
	
	如果咱们让hashSet存储 Student对象
		如果我认为 学生里面 姓名 年龄 相同了 我就认为是同一个人。 则Student 需要重写HashCode和equals方法
		//默认情况下,不同对象的哈希值是不相同的
       //通过方法重写,可以实现不同对象的哈希值是相同的
	   //System.out.println("重地".hashCode()); //1179395
     // System.out.println("通话".hashCode()); //1179395 String重写了HashCode方法

重写 equals和HashCode方法 package com.itcast;

						public class Student {
							private String name;
							private int age;
							public Student(){}
							public Student(String name, int age){
								this.name = name;
								this.age = age;
							}
							/*@Override
							public boolean equals(Object obj) {
								Student s = (Student)obj;
								return s.name.equals(name)&&s.age ==age;
							}*/

							@Override
							public boolean equals(Object o) {
								if (this == o) return true;                                           ////直接比较??
								if (o == null || getClass() != o.getClass()) return false;    ////getClass方法???

								Student student = (Student) o;

								if (age != student.age) return false;
								return name != null ? name.equals(student.name) : student.name == null;
							}

							@Override
							public int hashCode() {
								int result = name != null ? name.hashCode() : 0;
								result = 31 * result + age;
								return result;
							}
								

LinkedHashSet :不可以存储重复元素 存取有序


TreeSet :不可以存储重复元素 可以给元素排序(从小到大 或者从大到小)
	讨论题:
		1:TreeSet 为什么能排序 底层是什么结构 ?
		2:TreeSet 存 学生对象呢? 怎么排? 根据什么排序??

			一: Student 是实现一个Comparable 接口 并重写 compareTo方法。并把排序的规则 写在 compareTo方法里面。 
				存学生的时候,就会按照 你写的规则去排序。
				   (引入一个 第三方裁判。裁判就可以给你的元素比出大小来 从而让你TreeSet知道谁大谁小,进而排序 
				这个裁判是谁呢? 是Comparator接口的子类对象。 子类对象里面必须具备 compare(s1,s2)方法。)
			
			二:
				小明 和 小红 比较身高。  第一种比较方式: 小明 自己和 小红去比。
										 第二种比较方式: 小明找了老师过来,给他评比一下。 
	
	懵点:
		1:为什么 0 就是重复。 1就是就是 正序, -1就是 倒序。
		2:为什么 this -s  就是升序, s-this 就是倒序。
	
	
		
		//1、将字符串元素按照字典顺序排序,选择TreeSet集合。

		//2、String实现了Comparable接口,默认排序就是字典顺序。所以不需要在TreeSet集合的构造方法中传入参数。

		//3、TreeSet集合属于set体系,遍历方式为迭代器或者foreach语句。

	题目1:	
		在集合里面 存储 10个 1-100的随机数。然后遍历
		(要求集合里面的这10个随机数 不能重复。)

		
			
		
	题目:2:(和今天第11个视频内容一样)
		有一个学生类, 有这些属性, 数学成绩 math , 英语成绩 English , 语文 Chinese
		有5个学生, 按照学生的总成绩 从大到小排序。
		如果总成绩相同, 请按照 数学排
		如果总成绩同了 数学也同了,语文排。
		语文也同了,安英语排。
		英语也同了,按姓名排。
		姓名也同了,就是同一个人 去除掉。

	题目3:
		在集合里面 存储10个 1-20的随机数。
		然后不能有重复,然后  从大到小排序。 打印出来。
		(你可以试着做做 从大到小排序)

		TreeSet ts = new TreeSet();
		
		ts.add(100);
		ts.add(99);
		ts.add(101);

		// 99 100 101


		

	interface Inter {
		void show(String s , String s1);
	}


	class MyInter implements Inter {
		public void show(String s , String s1){
		
		}
	}

	Inter mi = new MyInter();
	mi.show("a","b");
	

	Inter i = new Inter(){
		public void show(String s , String s1){
		
		}
	};

	i.show("abbc","bdc");




	Cat extends Animal
	Cat implements Jumping;

	Animal a = new Cat();
	//Jumping j = a; // 编译报错。
	Jumping j = (Jumping)a ;// 编译成功 运行成功

标签:String,迭代,al,列表,lit,并发,add,集合
来源: https://www.cnblogs.com/zhang-blog/p/14249657.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有