多线程回顾、集合Collection、Set、List等基本知识
多线程回顾
问: 多线程的两种创建方式?
- 继承Thread类
- 实现Runnable接口
- 线程池
- Callable
问:多线程通常会遇到线程安全问题?
-
什么情况下会遇到线程安全问题?
答:一个数据被多个线程访问(有读有写)
-
解决这个问题的方式?
SE:同步锁 synchronized
A : 同步代码块
B : 同步方法
-
同步锁的要求
A : 这多个线程必须使用同一个锁对象
B : 同步锁的类型没有要求
-
同步方法的锁对象是谁?
A : 非静态方法 : this
B : 静态方法 : 当前类名.class
-
加同步锁的代码范围?
单词的原子性的任务代码
原子性 : 不可拆分,最小单位
以一次卖一张票为例 , 本次和卖一张票有关的代码需要加锁
判断票数是否够
票数减少
打印票号
问 : 线程通信
Object类的
-
wait方法 : 让当前线程等待 , 进入阻塞状态
-
notify和notifyAll
notify : 随机唤醒一个等待的线程
notifyAll : 唤醒所有等待的线程
它们必须由同步锁调用 . 否则会报illegalMoritorStateException异常
问 : 线程的生命周期 Thread类
- 新建
- 可运行
- 阻塞 : 不限时
- 限时的等待
- 等锁
- 终结
一、集合
1.1集合与数组有什么区别?
数组 : 存储和管理一组数据的容器 .
数组特点:
- 定长(数组长度不可变)
- 元素类型相同
- 索引从0开始
- 元素连续存储
- 元素既可以是基本数据类型 , 也可以是引用数据类型
集合 : 也是容器
集合的特点:
- 长度可变
- 元素类型相同
- 有的是有序的 , (即可以根据索引操作) , 有的是无序的 (即不能根据数组索引操作)
- 元素存储的结构很丰富 , 可能是数组 , 可能是链表等
- 元素必须是引用数据类型
1.2集合的类型有哪些?
集合的类型可以分为两大类 :
(1) Collection系列 : 存储一组对象
例如: [“张三”,“李四”,“王五”]
(2) Map系列 : 存储一组键值对(key,value)
例如:[1=“张三”,2=“李四”]
Collection系列:
(1) List : 列表 , 允许元素重复 , 有序(可以根据索引操作元素)
(2) Set : 集 , 不允许元素重复 , 无序的(不可以根据索引操作元素)
(3) Queue : 队列 , 元素先进先出
1.3java.util.Collection接口
1.添加元素
-
public boolean add(E e) : 添加一个元素
public class Exercise {public static void main(String[] args) {//Collection是这个系列集合的根接口//Collection coll = new Collection(); 是错误的,因为Collection是一个接口,不能直接new对象Collection coll = new ArrayList();//Collection的子接口List的实现类ArrayList 此处为多态引用,左边是父接口的类型,右边是实现类的对象coll.add("哈哈");coll.add("嘻嘻");coll.add("嘿嘿");System.out.println(coll); //自动调用ArrayList中重写的toString方法Collection coll2 = new ArrayList();coll2.add("丢丢");coll2.add("皮皮");System.out.println(coll2);coll.add(coll2);System.out.println(coll);} } //输出[哈哈, 嘻嘻, 嘿嘿] //[丢丢, 皮皮] //[哈哈, 嘻嘻, 嘿嘿, [丢丢, 皮皮]]
-
public boolean addAll(Collection<?extend E>c) : 添加一组元素 . 即把c集合中的一组元素添加到当前集合(this) . this = this ∪ c
public class Exercise {public static void main(String[] args) {//Collection是这个系列集合的根接口//Collection coll = new Collection(); 是错误的,因为Collection是一个接口,不能直接new对象Collection coll = new ArrayList();//Collection的子接口List的实现类ArrayList 此处为多态引用,左边是父接口的类型,右边是实现类的对象coll.add("哈哈");coll.add("嘻嘻");coll.add("嘿嘿");System.out.println(coll); //自动调用ArrayList中重写的toString方法Collection coll2 = new ArrayList();coll2.add("丢丢");coll2.add("皮皮");System.out.println(coll2);coll.addAll(coll2);System.out.println(coll);} } //输出: //[哈哈, 嘻嘻, 嘿嘿] //[丢丢, 皮皮] //[哈哈, 嘻嘻, 嘿嘿, 丢丢, 皮皮]
2、删除元素
-
public void clear() : 清空所有元素
public class API_clear {public static void main(String[] args) {Collection coll = new ArrayList();coll.add("哈哈");coll.add("嘻嘻");coll.add("嘿嘿");coll.add("biubiu");System.out.println(coll);//删除 clear();清空coll.clear(); //清空所有} } //输出 //[哈哈, 嘻嘻, 嘿嘿, biubiu] //
-
public boolean remove(Object o) : 在当前集合中找到与o相等的一个元素 , 然后删除它 , 并返回true , 如果没找到 , 就返回false
public class API_clear {public static void main(String[] args) {Collection coll = new ArrayList();coll.add("哈哈");coll.add("嘻嘻");coll.add("嘿嘿");coll.add("biubiu");System.out.println(coll);coll.remove("biubiu");System.out.println(coll);} } //输出 //[哈哈, 嘻嘻, 嘿嘿, biubiu] //[哈哈, 嘻嘻, 嘿嘿]
-
public boolean removeAll(Collection<?> c) : 从当前集合中删除所有和c集合中"相同的元素"
this = this - this ∩ c
public class API_removeAll {public static void main(String[] args) {Collection coll = new ArrayList();coll.add("哈哈");coll.add("嘻嘻");coll.add("嘿嘿");coll.add("biubiu");coll.add("diudiu");System.out.println(coll);Collection coll1 = new ArrayList();coll1.add("哈哈");coll1.add("biubiu");coll1.add("hello");System.out.println(coll1);coll.removeAll(coll1);//removeAll(c) 删除一组对象 删除掉coll ∩ c 元素//即 this = this - this ∩ cSystem.out.println(coll);} } //输出 //[哈哈, 嘻嘻, 嘿嘿, biubiu, diudiu] //[哈哈, biubiu, hello] //[嘻嘻, 嘿嘿, diudiu]
-
public boolean retainAll(Collection<?> c) : 从当前集合中删除所有和c集合中"不同的"元素 , 即当前集合中只留下和c集合相同的元素 . this = this ∩ c
public class API_retainAll {public static void main(String[] args) {Collection coll = new ArrayList();coll.add("哈哈");coll.add("嘻嘻");coll.add("嘿嘿");coll.add("biubiu");coll.add("diudiu");System.out.println(coll);Collection coll1 = new ArrayList();coll1.add("哈哈");coll1.add("biubiu");coll1.add("hello");System.out.println(coll1);coll.retainAll(coll1);System.out.println(coll);} } //输出 //[哈哈, 嘻嘻, 嘿嘿, biubiu, diudiu] //[哈哈, biubiu, hello] //[哈哈, biubiu]
-
public default boolean removeIf(Predicate<? super E>filter) : JDK8引入的 . 从当前集合中删除Predicate接口的实现类的test方法判断为true的元素 . 在Predicate接口的实现类中会重写一个boolean test(E element)方法 , 该方法用于判断当前集合的元素是否满足xx条件 .
在removeIf方法中 , 会遍历集合所有元素 , 并将元素作为实参传给test方法中的条件 , 则返回true , 该元素就会被删除 ; 该元素不满足test方法中的条件 , 则返回false , 该元素就会被保留
public class API_removeIf {public static void main(String[] args) {//需求:删除包含a字母的单词,现在要求根据条件删除//boolean removeIf(Predicate filter)//Predicate是一个接口,包含一个抽象方法 boolean test(Object t)//在这个抽想方法中,是编写判断t对象的条件 , 如果t对象满足xx条件 ,就返回true,如果不满足xx条件,就返回false//当我们把Predicate接口的实现类对象放到removeIf方法中,就表示满足test条件的,要被删除,不满足test的条件就不删除Collection coll = new ArrayList();coll.add("哈哈");coll.add("嘻嘻");coll.add("嘿嘿");coll.add("biubiu");System.out.println(coll);coll.removeIf(new Predicate() {@Overridepublic boolean test(Object o) {if(o instanceof String){/*String str = (String) o;if(str.contains("b")){return true;}else{return false;}*/return ((String)o).contains("b");}return false;}});System.out.println(coll);} } //输出 //[哈哈, 嘻嘻, 嘿嘿, biubiu] //[哈哈, 嘻嘻, 嘿嘿]
3、查询元素
- public boolean contains(Object obj):用于判断当前集合是否包含obj这个对象。
- public int size():用于返回当前集合的元素的总个数。
- public boolean isEmpty():判断当前集合是否为空。
- public Object[] toArray() :把当前集合中所有元素放到一个Object[]数组中返回。
- public boolean containsAll(Collection<?> c):用于判断当前集合是否包含c集合的所有对象。即判断c集合是否是当前集合的“子集”。如果c是this的子集,返回true,否则返回false。
public class API {@Testpublic void test() throws Exception{Collection coll = new ArrayList();coll.add("hello");coll.add("world");coll.add("java");coll.add("atguigu");coll.add("chailinyan");coll.add("chailinyan");//查询://(1)查询当前集合中是否有"java"这个单词System.out.println(coll.contains("java")); //true//(2)查询集合中元素的个数System.out.println(coll.size()); //6//(3)判断当前集合是否为空System.out.println(coll.isEmpty()); //false//(4)把集合的元素,放到一个数组中返回Object[] arr = coll.toArray();System.out.println(Arrays.toString(arr));//[hello, world, java, atguigu, chailinyan, chailinyan]//(5)查询是否包含一组对象Collection coll2 = new ArrayList();coll2.add("hello");coll2.add("java");System.out.println(coll.containsAll(coll2)); //truecoll2.add("dwt");System.out.println(coll.containsAll(coll2)); //false 因为添加新元素dwt后,coll2就不再是coll的子集}
}
4、遍历
- foreach循环遍历 IDEA快捷键iter
- public Iterator iterator():返回一个Iterator迭代器对象,用于遍历容器中的元素。
1.4增强for循环(foreach循环)
1、foreach循环语法格式
语法格式:
for(元素的类型 元素名 : 集合对象名或数组对象名){//遍历集合或数组元素要做的事
}
public class Test {@org.junit.Testpublic void test() throws Exception{Collection coll = new ArrayList();coll.add("hello");coll.add("world");coll.add("java");coll.add("atguigu");coll.add("dwt");for (Object obj : coll) {System.out.println(obj+"的长度:"+((String)obj).length());}}
}
2、增强for循环与普通for循环有什么区别
- 遍历数组 : 增强for循环没有下标 , 普通for循环有下标
- 普通for循环可以用于 , 重复执行某些代码的任意场景 , 但是增强for循环只能用于遍历集合与数组
3、是不是所有的集合/容器都可以使用foreach呐?
答 : 不是 , 只有实现了java.lang.Iterable接口的集合才可以使用增强for循环 , Collection接口继承了Ierable接口 , 所以Collection系列的集合都是Iterable接口的实现类 , Map系列的集合不支持增强for循环我们自己定义的集合想要使用增强for循环 , 就实现Iterable接口即可.
4、Iterable接口是否包含抽象方法呢?
答案 : 包含 抽象方法为: Iterator iterator()
5、Iterable与Iterator的联系
- 凡是实现Iterable接口的集合等类型 , 都包含了Iterator iterator() , 也就是说 , 必须重写该方法 , 要提供一个迭代器的实现类
- 对于foreach循环来说 , 对集合使用foreach , 本质上是用集合的迭代器在遍历
- foreach只是一个语法糖
- 遇到集合 , 就会转换为迭代器遍历
- 遇到数据 , 就会转换为普通for循环
- foreach只是一个语法糖
public class Collection_array {@Testpublic void test() throws Exception{Collection coll = new ArrayList();coll.add("hello");coll.add("world");coll.add("java");coll.add("atguigu");//使用foreach遍历集合for (Object o : coll) {System.out.print(o+" "); //看起来再使用foreach,本质上仍然是Iterator迭代器}System.out.println();System.out.println("------------------------");int[] arr = {1,2,3,4,5};for (int i : arr) {System.out.print(i+" ");}}
}
//输出
//hello world java atguigu
//------------------------
//1 2 3 4 5
6、Iteroator和Iterable的区别
1.5迭代器
1、迭代器遍历集合
迭代器的接口 : java.util.Iterator接口 , 包含两个抽象方法
- boolean hasNext() : 判断当前集合是否还有元素可迭代
- Object next() : 取出迭代器当前位置的元素,并让迭代器指向下一个元素的位置
public class Test {@org.junit.Testpublic void test() throws Exception{Collection coll = new ArrayList();coll.add("hello");coll.add("world");coll.add("java");coll.add("atguigu");//使用Iterator迭代器 遍历 coll集合的元素//需求:查看上面集合的所有元素,并且输出这些字符串的长度Iterator iterator = coll.iterator();//这里调用了集合的iterator()方法,得到是Iterator接口的实现类的对象//iterator迭代器对象的 作用 遍历 coll集合的元素while (iterator.hasNext()){ //判断集合是否还有元素可迭代Object obj = iterator.next(); //取出迭代器当前位置的元素,并让迭代器指向下一个元素的位置System.out.println(obj + "的长度:" + ((String)obj).length());}}
}
//输出:
hello的长度:5
world的长度:5
java的长度:4
atguigu的长度:7
2、对比Iterable和Iterator
java.lang.Iterable接口:可迭代的,形容词able结尾集合类型实现Iterable接口,表示集合可迭代的java.util.Iterator接口:迭代器,名词or专门有一些类实现Iterator接口,用于遍历或迭代集合的元素每一种集合都有自己的迭代器类型,这些迭代器类型通常都在集合的内部,以成员内部类方式存在这里涉及到一个设计模式,迭代器模式.
面向对象的开发原则:高内聚低耦合高内聚,ArrayList集合,它底层是数组,它内部有一个专用的迭代器Itr成员内部类可以直接访问外部类的所有的成员,包括私有的.这里表示迭代器可以访问到外部集合;类型的所有元素.而且这个迭代器Itr类型只为当前的ArrayList服务,所以选用成员内部类方式实现(体现高内聚)低耦合:外部使用这些集合的迭代器时,不需要关心它的内部打开类的搜索框快捷键 ctrl+N查看类的成员列表快捷键 alt + 7
3、用foreach还是lterator
问题 : 遍历集合既可以使用foreach , 又可以使用Iterator迭代器 , 那么到底用哪个?
- 如果只是查看元素 , 优先选择foreach , 代码更简洁、明了
- 如果在遍历集合元素过程中 , 要删除元素 , 只能用Iterator , 而不能用foreach
Iterator迭代器的意义:
- foreach本身用的就是迭代器
- 在Java8之前 , Collection集合是没有removeIf方法的 , 无法根据条件删除元素 , 所以迭代器Iterator接口提供了一个方法 , 用于在遍历集合元素的过程中 , 根据条件删除元素 . 当然 , 现在已经是jdk8及以上的版本了 , 可以直接使用Collection中的removeIf方法 , 优先选择它
4、Iterator迭代器删除元素问题
Iterator接口有一个方法 : void remove() , 用于删除迭代器刚刚遍历的集合元素
这个方法在早期是Iterator接口的一个抽象方法 (实现类必须重写) , java8以后 , 改为默认方法 (实现类可以重写 , 也可以不重写)
因为早期集合没有removeIf方法 , 所以 , 要根据条件删除元素时 , 必须使用迭代器一边遍历 , 一边判断条件 , 使用迭代器的remove方法 . Java8以后 , 引入了removeIf方法 , 开始建议大家使用removeIf方法 , 新的集合内部类的迭代器类型可以重写 , 也可以不重写迭代器的remove方法
@Test
public void test1() throws Exception{Collection coll = new ArrayList();coll.add("hello");coll.add("world");coll.add("java");coll.add("atguigu");//需求:删除"java//方法一:直接使用Collection中的remove()方法,在ArrayList中的实现// coll.remove("java");// System.out.println(coll);//方法二:使用迭代器遍历删除Iterator iterator = coll.iterator();while (iterator.hasNext()){Object obj = iterator.next();if("java".equals(obj)){iterator.remove();}}System.out.println(coll);
}
@Test
public void test3() throws Exception{Collection coll = new ArrayList();coll.add("hello");coll.add("world");coll.add("java");coll.add("atguigu");//需求:删除包含a字母的单词//方式二:JDK1.2之后都能用,迭代器删除Iterator iterator = coll.iterator();while (iterator.hasNext()){Object obj = iterator.next();if(((String)obj).contains("a")){iterator.remove(); //此处调用的时iterator的remove()方法}}
}
错误示范 , 在迭代器中用了Collection的remove方法 , 会发生异常java.util.ConcurrentModificationException
@Test
public void test4() {//foreach不能删除元素Collection coll = new ArrayList();coll.add("hello");coll.add("world");coll.add("java");coll.add("atguigu");//需求:删除包含a字母的单词//方式二:JDK1.2之后都能用,迭代器删除for (Object obj : coll) {if(((String)obj).contains("a")){coll.remove(obj); //此处调用的时Collection的remove()方法//编译没有问题 , 但是一运行就报错异常:java.util.ConcurrentModificationException }}
}
5、迭代器原理分析
ArrayList集合的相关变量:
Object[] elementData :数组,用于存储元素
int size:用于记录元素个数
int modCount:用于记录元素个数变化次数,添加或删除元素都会使得modCount值+nArrayList内部类Itr的相关变量:
int cursor:迭代器当前游标值,即迭代器当前指向elementData元素的下标值
int lastRet:迭代器刚刚访问过的元素下标值,如果迭代器还未访问过元素,或者刚刚访问过的元素已被删除,那么它的值为-1,表示该元素不存在了。
int exepectedModCount:迭代器“预计的”modCount值,它应该与ArrayList的modCount值相等,否则就说明集合在迭代器之外修改了集合,对集合做了添加或删除元素操作。要求:(1)迭代器的exepectedModCount始终要与集合的modCount一致。所以只有调用迭代器的remove删除方法,才能保证它们始终是一致的。(2)集合的元素删除了,迭代器应该回退一下,保证所有元素都被遍历和检查到。
总的结论 : 在使用foreach或Iterator迭代器遍历集合的过程中 , 千万不要调用集合的remove , add 等方法 , 如果要删除元素 , 调用迭代器的remove方法 .
二、Set集合
2.1Set集合类型
Set集合是Collection集合的一个分支
Collection是一个接口 , Set是它的子接口 . 而且Set这个子接口没有扩展新方法 , 用的都是Collection接口的方法 .
Set接口有很多实现类 , 其中比较常用的实现类 :
- HashSet : 元素是散列存储 , 看起来完全无规律
- LinkedHashSet : 元素也是散列存储 , 但是它内部有一个双向链表来记录元素的**“添加顺序”**
- 上面两个集合区分元素是否有重复 , 就看元素hashCode值和equals方法
- TreeSet : 元素有规律存储 , 按照元素的大小顺序存储 , 以二叉树存储 . 必须依赖Comprable接口或Comparator接口 , 如果是自定义类 , 则必须实现这两个比较接口才可以TreeSet
- 区分元素是否有重复 , 就是看元素大小是否相同
共同特征: 元素是不可重复的 , 无序的(这里无序的意思是Set接口没有提供通过索引来操作元素的方法)
//HashSet@Testpublic void testHashSet() throws Exception{HashSet hashSet = new HashSet();hashSet.add("hello");hashSet.add("java");hashSet.add("world");hashSet.add("haha");hashSet.add("haha");System.out.println(hashSet);}
//输出:[haha, java, world, hello]
可以看出 , HashSet是无序的 , 且元素不可重复 , 看起来毫无规律
//LinkedHashSet@Testpublic void testLinkedHashSet() throws Exception{LinkedHashSet linkedHashSet = new LinkedHashSet();linkedHashSet.add("hello");linkedHashSet.add("java");linkedHashSet.add("world");linkedHashSet.add("haha");linkedHashSet.add("java");System.out.println(linkedHashSet);}
//输出:[hello, java, world, haha]
可以看出 , LinkedHashSet元素也是不可重复的 , 但是看似有规律(规律为按照添加顺序排序)
//TreeSet自然排序@Testpublic void testTreeSet() throws Exception {//演示TreeSet用树存储,有规律,按照大小顺序排序(自然顺序)TreeSet treeSet = new TreeSet();treeSet.add("hello");treeSet.add("java");treeSet.add("world");treeSet.add("haha");treeSet.add("abc");treeSet.add("java");System.out.println(treeSet);//String类型的对象可以比较大小,因为String类实现了java.lang.Comparable自然比较接口,重写了 int compareTo(Object obj)}
//输出:[abc, haha, hello, java, world]自然排序 : 是按照字符串的字符的编码值比较大小如果两个字符串的前面字符全部相同 , 那么 短< 长
Comparable:以able结尾,形容词,表示可比较大小的哪个类的对象要比较大小,哪个类实现它即可String对象要比较大小,String类实现Comparable即可
Comparator:以or结尾,名称,表示比较器. 比较器的对象用于比较另外某个类的两个对象单独编写一个类,实现Comparator接口,例如 MyComparator类重写 int compare(Object o1,Object o2)MyComparator类的对象调用compare可以用来比较两个字符串的对象
//TreeSet定制排序 @Testpublic void testTreeSet1() throws Exception{//演示TreeSet用树存储,有规律,按照大小顺序排序(定制顺序:如按照字符串的长度排序)MyComparator m1 = new MyComparator();TreeSet treeSet = new TreeSet(m1);treeSet.add("hello");treeSet.add("java");treeSet.add("world");treeSet.add("haha");treeSet.add("abc");treeSet.add("java");System.out.println(treeSet);}
//输出[abc, haha, java, hello, world]
public class MyComparator implements Comparator {@Overridepublic int compare(Object o1, Object o2) {//运行时,o1和o2都是String类型String s1 = (String) o1;String s2 = (String) o2;int result = s1.length() - s2.length();//长度不同,看长度,长度不同看内容return result == 0 ? s1.compareTo(s2) : result;}
}
2.2hashCode方法和equals方法
1、java.lang.Object类
boolean equals(Object obj):比较两个对象是否相等。
int hashCode():相当于计算对象的身份证号,用对象的属性值计算对象的身份证号码。它就是一个int值。
hashCode方法的返回值的作用,只有1个,用于计算元素在HashSet、HashMap等和hash有关的集合中的存储位置。
2、重写hashCode方法要求
- 同一个对象,如果属性值没有改变,前后两次调用hashCode方法返回结果必须相同。
- 不同的两个对象,equals比较不同(返回false),hashCode方法按理说应该不同的,最好也不同,但是实际上可能存在相同。y=f(x)不同的x,可能得到相同的y。
- 相同的两个对象,equals比较相同(返回true),hashCode方法返回结果必须相同。
- 两个对象的hashCode值不同,那么equals方法一定返回false。
3、重写hashCode方法和equals方法的快捷键:Alt + Insert
public class Test1 {@Testpublic void test() throws Exception{//员工目前没有重写hashCode方法Student s1 = new Student("张三", 18); //重写前 1012570586 重写后 24022538Student s2 = new Student("张三", 18); //重写前 1207140081 重写后 24022538System.out.println(s1.hashCode());System.out.println(s2.hashCode());/** hashCode是一个int值,它是根据对象的"特征"用散列函数计算出来的一个int值* 不同品牌的JVM,对于Object类的hashCode方法的计算规则不一样* 有的JVM里面是用内存定制作为对象特征,来计算hashCode值* 有的JVM里面是用对象的属性值作为对象的特征,来计算hashCode值** Object类的equals方法的源码是 this==obj , 比较地址值** 子类通常会重写hashCode方法,一般都是对对象的属性值作为对象的特征,来计算hashCode值* 两个对象属性值相同,hashCode值应该相同* 两个对象属性值相同,equals方法应该也相同* */}@Testpublic void test2() throws Exception{HashSet hashSet = new HashSet();hashSet.add("hello");hashSet.add("java");hashSet.add("world");hashSet.add("haha");hashSet.add("Aa");hashSet.add("BB");System.out.println(hashSet);}
}
2.3概念比喻
Collection集合:比喻,篮子、箱子,一种容器,用来装东西,Java中用来装对象的。
Iterable接口:表示可迭代,比喻是列车,上面可以去查看乘客的个数、乘客的情况 (验票)
Iterator接口:表示迭代器,比喻乘务员。为列车和列车上的乘客的服务。迭代器为集合和集合的元素服务的。
Comparable接口:自然比较接口。自然比较规则,通常是默认的,首先想到的比较规则。
举个例子:两个学生,要比较大小。通常是比较年龄,学生类实现Comparable接口,默认按照年龄比较大小。
Comparator接口:定制比较器接口。
举个例子:两个学生,要比较大小。定制是比较身高,成绩等。这个时候,需要老师这个角色,这个人作为比较器,查看两个学生的身高(体育老师),成绩(Java老师)。不同的老师,充当不同的比较器的角色。如果有多种比较的需求,就需要定义多个比较器的类。
Object类有两个方法:
boolean equals(Object obj):比较两个对象是否相等。
int hashCode():返回int对象的身份证号码。相当于用一个整数值代表一个对象的特征。
Set:是一种特殊的集合,无序和不可重复。如果数学好的同学,可以把它直接理解为数学中的集的概念。
三、List集合
3.1List集合的特征
List是有序的 , 可重复的
public class TestList {@Testpublic void test() throws Exception{ArrayList arrayList = new ArrayList();arrayList.add("张三");arrayList.add(0,"李四");arrayList.add("张三");System.out.println(arrayList);System.out.println(arrayList.get(2));}
}
//输出[李四, 张三, 张三]
//张三
3.2List接口的方法
List接口是Collection的子接口
1、添加
-
public void add(int index, E element):把新元素element添加到指定到当前集合列表的[index]位置。
-
public boolean addAll(int index, Collection<? extends E> c):将c集合的所有元素添加到指定到当前集合列表的[index]位置。
@Testpublic void test2() throws Exception{ArrayList arrayList = new ArrayList();arrayList.add("张三");arrayList.add(0,"李四");arrayList.add("张三");ArrayList arrayList1 = new ArrayList();arrayList1.add("熊大");arrayList1.add("熊二");arrayList1.add("光头强");//public boolean addAll(int index, Collection<? extends E> c)//需求:将arrayList1中所有的元素插入的arrayList中的最前面arrayList.addAll(0,arrayList1);System.out.println(arrayList);} //输出 [熊大, 熊二, 光头强, 李四, 张三, 张三]
2、删除
-
public E remove(int index):删除当前集合列表中[index]位置的元素,并返回被删除元素。
@Testpublic void test3() throws Exception{ArrayList arrayList = new ArrayList();arrayList.add("张三");arrayList.add(0,"李四");arrayList.add("张三");ArrayList arrayList1 = new ArrayList();arrayList1.add("熊大");arrayList1.add("熊二");arrayList1.add("光头强");arrayList.addAll(0,arrayList1);//需求:删除索引3位置上的元素//public E remove(int index)arrayList.remove(3);System.out.println(arrayList);} //输出:[熊大, 熊二, 光头强, 张三, 张三]
3、修改
-
public E set(int index, E ele):替换当前集合列表中[index]位置的元素,并返回被替换的元素。
-
public default void replaceAll(UnaryOperator operator):JDK8引入的。实现UnaryOperator接口时必须重写public E apply(E oldValue) 方法。在replaceAll方法中会遍历集合的所有元素,并将每一个元素作为实参传给apply方法,然后用apply方法的返回值作为newValue替换该元素。
-
pubilc default void sort(Comparator<? super E> c):使用定制比较器对象c,对当前集合列表的元素排序。
//set@Testpublic void test4() throws Exception{ArrayList arrayList1 = new ArrayList();arrayList1.add("熊大");arrayList1.add("熊二");arrayList1.add("光头强");//需求:把索引2上的元素,替换为"灰太狼"//public E set(int index, E ele) 替换当前集合列表中[index]位置的元素,并返回被替换的元素Object o = arrayList1.set(2, "灰太狼"); //返回被替换的元素System.out.println(o);System.out.println(arrayList1);} //输出 光头强 [熊大, 熊二, 灰太狼]
//void replaceAll(UnaryOperator<E> operator)@Testpublic void test5() throws Exception{ArrayList arrayList1 = new ArrayList();arrayList1.add("熊大");arrayList1.add("熊二");arrayList1.add("光头强");arrayList1.add("光头强");arrayList1.add("高启强");arrayList1.add("超人强");/*** void replace(UnaryOperator operator)形参类型 UnaryOperator接口* 这个接口有一个抽象方法 T apply(T t)* 调用replaceAll方法:需要传入一个UnaryOperator接口的实现类对象* 重写 T apply(T t): t是原来的元素,apply方法返回的值是 新的元素* t代表list集合中的这些主人公元素* apply方法的返回值分两种情况:* (1)如果t不包含"强",则返回t* (2)如果t包含"强",则返回"GGB"*/arrayList1.replaceAll(new UnaryOperator() {@Overridepublic Object apply(Object obj) {/*String str = (String) obj;if(str.contains("强")){return "GGB";}else{return obj;}*///可以简写如下return ((String)obj).contains("强") ? "GGB" : obj;}});System.out.println(arrayList1);} //[熊大, 熊二, GGB, GGB, GGB, GGB]
//pubilc default void sort(Comparator<? super E> c) @Testpublic void test6() throws Exception {ArrayList list = new ArrayList();list.add(1);list.add(5);list.add(3);list.add(2);System.out.println(list); //List是有序的 此时应该输出[1,5,3,2]list.sort(new Comparator() {@Overridepublic int compare(Object o1, Object o2) {return (Integer) o1 - (Integer) o2;}});System.out.println(list); //输出[1,2,3,5]}
4、查询
- public E get(int index):返回当前集合列表中[index]位置的元素
- public List subList(int fromIndex, int toIndex):返回当前集合列表中[fromIndex, toIndex)范围的元素
-
public int indexOf(Object obj):在当前集合列表中查询obj元素的位置,如果存在多个obj,则返回第1次出现的位置。
-
int lastIndexOf(Object obj):在当前集合列表中查询obj元素的位置,如果存在多个obj,则返回最后1次出现的位置。
@Testpublic void test7() throws Exception{ArrayList list = new ArrayList();list.add("光头强");list.add("熊大");list.add("光头强");list.add("熊二");list.add("光头强");System.out.println(list.indexOf("光头强"));//[0]System.out.println(list.lastIndexOf("光头强"));//[4]System.out.println(list.get(1));//熊大System.out.println(list.subList(2,4));//[光头强, 熊二] 含头不含尾, 等价于 左闭右开 [2,4)}
{
return (Integer) o1 - (Integer) o2;
}
});
System.out.println(list); //输出[1,2,3,5]
}
### 4、查询- public E get(int index):返回当前集合列表中[index]位置的元素
- public List subList(int fromIndex, int toIndex):返回当前集合列表中[fromIndex, toIndex)范围的元素* public int indexOf(Object obj):在当前集合列表中查询obj元素的位置,如果存在多个obj,则返回第1次出现的位置。* int lastIndexOf(Object obj):在当前集合列表中查询obj元素的位置,如果存在多个obj,则返回最后1次出现的位置。~~~java
@Testpublic void test7() throws Exception{ArrayList list = new ArrayList();list.add("光头强");list.add("熊大");list.add("光头强");list.add("熊二");list.add("光头强");System.out.println(list.indexOf("光头强"));//[0]System.out.println(list.lastIndexOf("光头强"));//[4]System.out.println(list.get(1));//熊大System.out.println(list.subList(2,4));//[光头强, 熊二] 含头不含尾, 等价于 左闭右开 [2,4)}
相关文章:
多线程回顾、集合Collection、Set、List等基本知识
多线程回顾 问: 多线程的两种创建方式? 继承Thread类实现Runnable接口线程池Callable 问:多线程通常会遇到线程安全问题? 什么情况下会遇到线程安全问题? 答:一个数据被多个线程访问(有读有写) 解决这个问题的方式? SE:同步锁 synchronized A : 同步代码块 B : 同步方法…...
分享5款用起来很好用的软件,总有一款适合你
很多软件用起来很好用,但是由于这样那样的原因,一直没什么知名度,但是不代表它们不好用,我的任务就是把这些宝藏分享给大家。 1.图像处理——Photoscissors Photoscissors是一款在线图像背景移除工具,可以让你轻松地从…...
大数据学习1.5-单机Hadoop
1.修改主机信息 vi /etc/hosts 2.修改信息如下(这里第三位一定是自己的IP 每个人都不一样) 192.168.216.140 hadoop01 192.168.216.141 hadoop02 192.168.216.142 hadoop033.修改Hadoop配置信息-1进入配置信息文件 cd /usr/local/hadoop/hadoop-2.7.1/etc/hadoop/ 4.修改Had…...
Cesium对实体元素鼠标点击popup div信息框
一、简介 设置div信息框模板,给实体元素绑定事件,同步空间位置,然后在回调函数弹出信息框。 二、示例源码 <!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" …...
有多条业务线,mysql建多库多表比较好还是一个库多个表比较好呢?
这个问题的答案取决于您的具体需求。以下是一些需要考虑的因素: 数据独立性:如果您的业务线之间的数据是独立的,并且不太可能需要进行跨业务线的查询,那么将它们分成多个数据库可能是有意义的。这样可以使每个业务线的数据更加独…...
C++---异常处理
异常处理 异常处理try语句块和throw表达式异常的抛出和捕获异常的抛出和匹配原则 异常安全异常规范标准异常 异常处理 异常是指存在于运行时的反常行为,这些行为超出了函数正常功能的范围。当程序的某部分检测到一个他无法处理的问题时,需要用到异常处理…...
接口自动化测试(Python+Requests+Unittest)
(1)接口自动化测试的意义、前后端分离思想 接口自动化测试的优缺点: 优点: 测试复用性。 维护成本相对UI自动化低一些。 为什么UI自动化维护成本更高? 因为前端页面变化太快,而且UI自动化比较耗时(比如等待页面元素的…...
驱动开发,IO多路复用(select,poll,epoll三种实现方式的比较)
1.IO多路复用介绍 在使用单进程或单线程情况下,同时处理多个输入输出请求,需要用到IO多路复用;IO多路复用有select/poll/epoll三种实现方式;由于不需要创建新的进程和线程,减少了系统资源的开销,减少了上下…...
大数据-玩转数据-oracel字符串分割转化为多列
一、建表 create table split_string_test(id integer primary key,test_string varchar2(500) );二、插入测试数据 insert into split_string_test values(1, 10,11,12,13,14,22); insert into split_string_test values(2, 22,23,24); insert into split_string_test valu…...
GCP设置Proxy来连接Cloud SQL
在之前的文章用Google CDC来同步Cloud SQL的数据到Bigquery_gzroy的博客-CSDN博客中,我通过在一个VM上设置反向代理的方式,使得Datastream可以通过私用连接连到Cloud SQL数据库进行数据复制。但是这种方式不太方便,主要是VM的状态我们不太方便…...
Python:为何成为当下最热门的编程语言?
文章目录 🍋引言🍋1. 简单易学🍋2. 多领域应用🍋3. 强大的社区支持🍋4. 丰富的库和框架🍋5. 跨平台兼容🍋6. 开源和免费🍋7. 数据科学和人工智能的崛起🍋8. 自动化和脚本…...
【echarts入门】:vue项目中应用echarts
一.安装echarts 在项目集成终端下载echarts npm install echarts --save 二.全局引入 创建/components/echarts/index.js // 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。 import * as echarts from "echarts/core";/** 引入任…...
Seata 源码篇之AT模式启动流程 - 上 - 02
Seata 源码篇之AT模式启动流程 - 02 自动配置两个关键点 初始化初始化TM初始化RM初始化TC 全局事务执行流程TM 发起全局事务GlobalTransactional 注解处理全局事务的开启 TM 和 RM 执行分支事务IntroductionDelegatingIntroductionInterceptorDelegatePerTargetObjectIntroduct…...
FFMPEG视频压缩与Python使用方法
一、简介 FFMPEG 是一个完整的,跨平台的解决方案,记录,转换和流音频和视频。 官网:https://ffmpeg.org/ 二、安装 1、Linux: sudo apt install ffmpeg 2、Mac: brew install ffmpeg 3、Windows: 下载文件&#…...
SpringMVC自定义注解---[详细介绍]
一,对于SpringMVC自定义注解概念 是一种特殊的 Java 注解,它允许开发者在代码中添加自定义的元数据,并且可以在运行时使用反射机制来获取和处理这些信息。在 Spring MVC 中,自定义注解通常用于定义控制器、请求处理方法、参数或者…...
5.4 转换数据
5.4 转换数据 5.4.1 哑变量处理类别型数据5.4.2 离散化连续型数据1、等宽法2、等频法3、聚类分析法 数据集 E:/Input/ptest.csv 5.4.1 哑变量处理类别型数据 数据分析模型中有相当一部分的算法模型都要求输入的特征为数值型,但实际数据中特征的类型不一定只有数值…...
雷池社区WAF:保护您的网站免受黑客攻击 | 开源日报 0918
keras-team/keras Stars: 59.2k License: Apache-2.0 Keras 是一个用 Python 编写的深度学习 API,运行在机器学习平台 TensorFlow 之上。它 简单易用:减少了开发者认知负荷,使其能够更关注问题中真正重要的部分。灵活性强:通过逐…...
链表反转-LeetCode206
**题目:**给你单链表的头结点head,请反转链表,并返回反转后的链表。 示例: 输入:head [1,2,3,4,5] 输出:[5,4,3,2&#x…...
北邮22级信通院数电:Verilog-FPGA(3)实验“跑通第一个例程”modelsim仿真及遇到的问题汇总(持续更新中)
北邮22信通一枚~ 跟随课程进度更新北邮信通院数字系统设计的笔记、代码和文章 持续关注作者 迎接数电实验学习~ 获取更多文章,请访问专栏: 北邮22级信通院数电实验_青山如墨雨如画的博客-CSDN博客 注意:本篇文章所有绝对路径的展示都来自…...
4G工业路由器,开启智能工厂,这就是关键所在
提到工业物联网,首先联想到的就是数据传输。要把海量的工业数据从设备端传到控制中心,无线数传终端就发挥着重要作用。今天就跟着小编来看看它的“联”是怎么建立的吧! 原文:https://www.key-iot.com/iotlist/1838.html 一提到无线数传终端,相信大家首先想到的是…...
计组-机器字长、存储字长、指令字长以及和他们有关的机器位数
🌳🌳🌳前言:本文总结了机器字长、存储字长、指令字长的概念以及和它们相关的机器位数。 目录 字长 机器字长 指令字长 存储字长 寄存器的位数 总结 字长 🌟字长一个字中的二进制位数。 🌟字长由微处…...
解决express服务器接收post请求报错:“req.body==> undefined“
现象如下: 解决办法:在代码中加入body-parser解析 const bodyParser require("body-parser"); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); 参考: How to fix "req.body undefined&q…...
5.zigbee的开发,串口putchar重定向(使用print),单播实验,usb抓包实验
一。实验:单播 实验要求: 实现终端定时向协调器发送给“好好学习”字符串,并且从终端打印出来。 要求: 指定端点为 0x0005 指定簇为 0x0003 1.进入应用层SampleApp.c中,串口的重定向 报错ÿ…...
解决AU报“MME无法使用“问题
今天在Adobe Audition(简称AU)软件,打开麦克风时,弹出如下错误:“加载默认的输入和输出设备失败:MME设备内部错误”,如图(1)所示: 图(1) AU报“MME设备内部错误” 继续点击AU菜单栏上的【编辑】–》首选项–》音频硬件,…...
Maven 安装配置
Maven 安装配置 文章目录 Maven 安装配置一、下载 Maven二、解压Maven核心程序三、指定本地仓库四、配置阿里云镜像仓库4.1 将原有的例子配置注释掉4.2 加入新的配置 五、配置 Maven 工程的基础 JDK 版本六、配置环境变量6.1 检查 JAVAHOME 配置是否正确6.2 配置 MAVENHOME6.3 …...
vscode 配置网址
首先我的项目是一个面向医院的系统 我是在三个文件里都配置了网址 第一个文件:vue.config.js const path require(path) const webpack require(webpack) const createThemeColorReplacerPlugin require(./config/plugin.config)function resolve (dir) {retu…...
git 本地工作区和仓库区基本使用
(1)git 本地有三个区 工作区和暂存区和 git管理的仓库. (自行动手实践理解,然后就入门了)(2)本地初次使用git做的事情,需要做如下工作 git config --global user.name "xx" git config --global user.email xxxqq.com git config --globa…...
有效的括号(栈的高频面试题)
一、题目描述 题目连接:有效的括号 给定一个只包括 (,),{,},[,] 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。左括号必须以正确的顺…...
GIS跟踪监管系统电子围栏
GIS跟踪监管系统电子围栏 (1)电子围栏展示。① 显示:② 隐藏:(2)电子围栏修改。① 新增电子围栏。② 修改电子围栏。工具箱(1)测量。① 测量距离:② 测量面积:…...
蓝桥杯2023年第十四届省赛真题-买瓜--Java题解
目录 蓝桥杯2023年第十四届省赛真题-买瓜 题目描述 输入格式 输出格式 样例输入 样例输出 提示 【思路解析】 【代码实现】 蓝桥杯2023年第十四届省赛真题-买瓜 时间限制: 3s 内存限制: 320MB 提交: 796 解决: 69 题目描述 小蓝正在一个瓜摊上买瓜。瓜摊上共有 n 个…...
曲靖公司网站建设/搜狗seo快速排名公司
题目描述 给定数字0-9各若干个。你可以以任意顺序排列这些数字,但必须全部使用。目标是使得最后得到的数尽可能小(注意0不能做首位)。例如:给定两个0,两个1,三个5,一个8,我们得到的…...
手机邮箱申请免费注册/seo最强
资料图:正在起飞的客运飞机。 中新网客户端北京1月15日电 (记者 程春雨)“为避免出现热点地区拥堵和票价过高情况,民航局在上海浦东、成都双流、三亚凤凰等10个热点机场开展国内航班延长运行时间试点,增加了航空公司统筹运力安排的灵活性&…...
网站推广建站/网页代码大全
vc6中的模板偏特化 我们都知道,vc6模板不支持偏特化。 近日偶然心血来潮,偏要试试在vc6中也来实现一些偏特化才能够做到的例子。 先做一个简单的,求m,n的最大公约数。一般函数如下: int gcd(int m, int n) { if (n 0) return m; …...
网站上的qq如何做悬浮/百度app下载安装官方免费下载
目录 1. 保持好奇,勤于在项目中发现问题 2.带着问题去深度思考、查各种资料 4. 将你的成果用起来,提升项目效果 1. 精力高度专注 2. 规律时间投入 很多同学都和我说过一个问题,有心想扎实地提高技术能力,但无奈工作太忙没有时…...
俄文企业网站建设/整合营销传播名词解释
1、实现效果: 案例描述:当用户单击不同的导航时,与其对应的内容回相应的呈现。 案例要求:使用jquery制作实现tab选项卡单击切换效果。 2、实现思路: (1)divcss布局,制作选项卡和对…...
网站建设 徐州/网络营销包括的主要内容有
1 假如你修改了一个文件中的内容,但是过了很久你忘了修改了哪里,可以这样: 比如你在一个文件分别三次修改了一些内容,如何回退显示你某次的内容那,我在我电脑上一个文件分别三次写了: op ok oc三个单词&a…...