多线程回顾、集合Collection、Set、List等基本知识

多线程回顾

问: 多线程的两种创建方式?

  1. 继承Thread类
  2. 实现Runnable接口
  3. 线程池
  4. Callable

问:多线程通常会遇到线程安全问题?

  1. 什么情况下会遇到线程安全问题?

    答:一个数据被多个线程访问(有读有写)

  2. 解决这个问题的方式?

    SE:同步锁 synchronized

    A : 同步代码块

    B : 同步方法

  3. 同步锁的要求

    A : 这多个线程必须使用同一个锁对象

    B : 同步锁的类型没有要求

  4. 同步方法的锁对象是谁?

    A : 非静态方法 : this

    B : 静态方法 : 当前类名.class

  5. 加同步锁的代码范围?

    单词的原子性的任务代码

    原子性 : 不可拆分,最小单位

    以一次卖一张票为例 , 本次和卖一张票有关的代码需要加锁

    ​ 判断票数是否够

    ​ 票数减少

    ​ 打印票号

问 : 线程通信

​ Object类的

  1. wait方法 : 让当前线程等待 , 进入阻塞状态

  2. notify和notifyAll

    notify : 随机唤醒一个等待的线程

    notifyAll : 唤醒所有等待的线程

    它们必须由同步锁调用 . 否则会报illegalMoritorStateException异常

问 : 线程的生命周期 Thread类

  1. 新建
  2. 可运行
  3. 阻塞 : 不限时
  4. 限时的等待
  5. 等锁
  6. 终结

一、集合

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 ∩ c
            System.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() {
                @Override
                public 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 {
    @Test
    public 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));        //true
        coll2.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.Test
    public 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循环
public class Collection_array {
    @Test
    public 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 
1694754249609
6、Iteroator和Iterable的区别

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.5迭代器

1、迭代器遍历集合

迭代器的接口 : java.util.Iterator接口 , 包含两个抽象方法

  • boolean hasNext() : 判断当前集合是否还有元素可迭代
  • Object next() : 取出迭代器当前位置的元素,并让迭代器指向下一个元素的位置
public class Test {
    @org.junit.Test
    public 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值+n
    
ArrayList内部类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
	 @Test
    public 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
	@Test
    public 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自然排序
	@Test
    public 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定制排序	
	@Test
    public 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 {
    @Override
    public 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 {
    @Test
    public void test() throws Exception{
        //员工目前没有重写hashCode方法
        Student s1 = new Student("张三", 18); //重写前 1012570586    重写后 24022538
        Student s2 = new Student("张三", 18); //重写前 1207140081    重写后 24022538

        System.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方法应该也相同
        * */

    }

    @Test
    public 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 {
    @Test
    public 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]位置。

    	@Test
        public 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]位置的元素,并返回被删除元素。

    	@Test
        public 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
    	@Test
        public 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)
    	@Test
        public 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() {
                @Override
                public 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)
    @Test
        public 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() {
                @Override
                public 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次出现的位置。

    @Test
        public 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
@Test
    public 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)
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值