泛型 and 集合

目录

一、泛型

1.定义

2.用法

2.1 用在类上

2.2 用在子类上

2.3 用在方法上

3.通配符

3.1  ?

3.3  上边界 

3.3  下边界

 二、集合

一、Collection(父接口)

1 .常用的方法

​编辑

2. 集合的遍历

(一)List子接口

 1. 常用方法

2. 遍历

(二)Queue 子接口

1. 常用方法

​编辑

2. 子接口 Deque

(三)Set接口

(一)HashSet类

LinkedHashSet类

(二)TreeSet

二、Map

    常用方法:

   遍历


一、泛型

1.定义

      顾名思义广泛的类型,在定义时候不确定之后要使用什么类型,所以使用泛型。在定义时候用一个字母去代替引用类型和包装类型,这样使用时可以使用泛型给形参赋值类型名

注意:泛型参数只能赋值引用类型和包装类型,不能赋值八大基本数据类型

2.用法

2.1 用在类上

      一般用在类名后,用尖括号括起来,使用大写字母作为参数

import java.util.Date;

public class AClass<T>{
    //定义
    private T name;
    public AClass(T t){
        name = t;
    }
    //调用
    public static void main(String[] args) {
        //左边和右边的尖括号都要写
        AClass<String> a = new AClass<String>("hello");
        //右边尖括号的类型可以省略 传入的不是String类型也会报错
        AClass<String> b = new AClass<>("world");
        //泛型参数为long类型
        AClass<Long> c = new AClass<>(1l);
        //泛型参数为Date类型
        Date date = new Date();
        AClass<Date> d = new AClass(date);
    }
}

特点:

1.左边和右边的尖括号都要写

2.左边的尖括号里必须写类型 否则编译器直接报错

3.右边尖括号的类型可以省略 传入的不是左边括号里的类型也会报错

下图为一些编译器报错案例

2.2 用在子类上

1.如果一个类继承了泛型类,那么在定义子类时候就给泛型参数赋值

public class Father<T> {
    private T name;

    public Father(T name) {
        this.name = name;
    }
}
class Son extends Father<String> {
    public Son(String name) {
        super(name);
    }
}

2. 如果不赋值,默认是Object类型

public class Father<T> {
    private T name;

    public Father(T name) {
        this.name = name;
    }
}

class Daughter extends Father{
    public Daughter(Object name) {
        super(name);
    }
}

3.子类的泛型参数可以赋值给父类的泛型参数

public class Father<T> {
    private T name;

    public Father(T name) {
        this.name = name;
    }
}
class Son<E> extends Father<E> {
    public Son( E name) {
        super(name);
    }
}
2.3 用在方法上

           位置:尖括号写在修饰符的后面

泛型方法在调用期间不需要指定具体类型,只需要传人具体对象 

编译器会自动推断对象的类型 //泛型方法调用期间并没有给泛型参数赋值

下面是dog1给a,  dog2给b赋值 没有给T赋值

import java.util.Objects;

public class MyTest {

    public static void main(String[] args) {
        Dog dog1 = new Dog("haha");
        Dog dog2 = new Dog("heihei");
        boolean result = MyTest.equals(dog1, dog2);
        System.out.println(result);
        
    }
    public static<T> boolean equals(T a, T b){
        return a.equals(b);
    }


}
class Dog  {
    String name;
    public Dog(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Dog dog = (Dog) o;
        return Objects.equals(name, dog.name);
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(name);
    }
}

3.通配符

3.1  ?

           不确定的类型,表示不关心传入的类型,可以是Long 也可以是Integer

public class MyTest {

    // 通配符 ? 不关心调用时候的具体类型
    public static void print(List<?> list){
        for(int i = 0;i<list.size();i++){
            System.out.println(list.get(i));
        }
    }
    public static void main(String[] args) {
        print(new ArrayList<String>());
        print(new ArrayList<Integer>());
       
    }
}
3.3  上边界 

          <? extends 上边界类型>

          可以是 上边界的任何子类型或者是本类型

public class MyTest {
    
    //上边界 <? extends 具体类型>
    public static void print2(List<?extends Number> list){
        for(int i = 0;i<list.size();i++){
            System.out.println(list.get(i));
        }
    }
    public static void main(String[] args) {
        print2(new ArrayList<Long>());
        print2(new ArrayList<Integer>());
        print2(new ArrayList<Number>());
       
    }

}

注意:不可以是其他不相关的类型

报错解析:因为Date类和Number 没有关系,只能是Number类的子类或者Number本类

3.3  下边界

       <? super 下边界类型>

       可以是本类型,也可以是本类型的父类

public class MyTest {

   
    public static void print3(List<? super Number> list){
        for(int i = 0;i<list.size();i++){
            System.out.println(list.get(i));
        }
    }
    public static void main(String[] args) {
        print3(new ArrayList<Number>());
        print3(new ArrayList<Object>());
    }

}

        和上边界一样,不能是其他不相关的类型

 二、集合

一、Collection(父接口)

接口List Set Queue都实现了Collection接口

ArrayList Vector LinkedList类都实现了List接口

hashSet 和 TreeSet 类都实现了Set接口,LinkedHashSet继承了HashSet类

Deque接口实现了 Queue接口

linkedList类实现了Deque接口

1 .常用的方法
  •          E sdd(E e):添加元素到集合中
  •          addAll( collection cl )  : 将cl集合添加到这个集合中
  •          int size : 返回集合中元素的个数
public class CollectionTest {
    public static void main(String[] args) {
        Collection<Integer> c1 = new ArrayList<>();
        c1.add(1);
        System.out.println("c1:"+c1);
        Collection<Integer> c2 = new ArrayList<>();
        c2.add(2);
        c2.add(3);
        System.out.println("c2:"+c2);
        c1.addAll(c2);
        System.out.println("将c2添加到c1后:"+c1);
        int sum = c1.size();
        System.out.println("c1的大小为:"+sum);
    }
}

  •          boolean isEmpty():  判断集合是否为空
  •          boolean contains(Object o) :判断集合中是否有o
  •          boolean containsAll( Collection c) : 查看调用者是否包含集合c
  •          boolean equals (Collection c): 查看两个集合是否相等
public class CollectionTest02 {
    public static void main(String[] args) {
        Collection<String> c1 = new ArrayList<>();
        c1.add("我爱");
        c1.add("中国");

        boolean b = c1.isEmpty();
        System.out.println("c1是否为空:"+b);

        b = c1.contains("中国");
        System.out.println("c1中是否含有中国:"+b);

        Collection<String> c2 = new ArrayList<>();
        c2.add("我爱");

        b = c1.containsAll(c2);
        System.out.println("c1是否包含c2:"+b);
        System.out.println(c1);
        System.out.println(c2);

        b = c1.equals(c2);
        System.out.println("c1是否等于c2:"+b);
    }
}

  •         boolean remove(Object o): 移除c1里面的元素 o ,只移除第一个o
  •         boolean removeAll(Collection c): 从集合中删除集合c中的所有元素
  •         boolean retainAll (Collection c) : 移除 调用集合中的 所有元素 除了集合c中的
  •         void clear(): 清空集合中的所有元素
  •         String toString() 打印集合中的所有元素,默认调用
public class CollectionTest03 {
    public static void main(String[] args) {
        Collection<Integer> c = new ArrayList<>();
        c.add(1);c.add(2);c.add(3);c.add(1);
        c.add(2);c.add(4);c.add(5);c.add(6);
        System.out.println("原始c的集合:"+c);
        c.remove(1);
        System.out.println("c集合移除第一个1 后"+c);

        Collection<Integer> c2 = new ArrayList<>();
        c2.add(1);
        c2.add(2);
        System.out.println("c2:"+c2);
        c.removeAll(c2);
        System.out.println("c删除c2集合中的所有元素后"+c);

        Collection<Integer> c3 = new ArrayList<>();
        c3.add(3);
        c3.add(4);
        System.out.println("c3中的元素:"+c3);
        c.retainAll(c3);
        System.out.println("c保留c3集合中的元素后"+c);
        c.clear();
        System.out.println("c清空后"+c);
    }
}

2. 集合的遍历

      1. 增强for循环

public class Test {
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<>();
        c.add("A");
        c.add("B");
        c.add("C");
        for(String s : c){
            System.out.println(s);
        }
    }
}

   2. 迭代器遍历

public class Test {
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<>();
        c.add("A");
        c.add("B");
        c.add("C");
        Iterator it = c.iterator();
        while(it.hasNext()){
            String s = (String)it.next();
            System.out.println(s);
        }
    }
}

注意: 迭代器遍历过程中不允许对集合进行修改长度

也就是说不能使用集合的方法删除元素,但是可以用迭代器的remove()删除

这涉及到底层源码 

源迭代器码解析:

  三个成员变量

          cursor : 记录下一次要返回的元素的下标

          lastret : 记录上一次刚刚返回的元素的下标

          expectedModCount :预计的修改次数 默认值为集合的长度 与modCount值息息相关

注意: 集合在调用add()方法添加元素是 modCount++ 

 hasNext(): return cursor != size: 当光标的值为集合长度时候,说明没有下一个元素

     next():

 1.检查预计修改次数和modCount是否一致,如果不一致,抛出 ConcurrentModificationException 异常

2. 光标的值先赋值给lastRet,相当于指针后移,光标的值+1,为下一次hasNext()做准备

 新的lastRet的值就是指针指向的元素下标,也就是刚刚取出来的元素

   remove():  

1. expectedModCount 和modCount 是否一致,如果不一致,抛出异常 

2. 调用ArrayList的E remove(int index)做真正的删除操作

     而E remove(int index) 里面调用System.arrcopy()方法,

从指定的index+1处,向前移动一位,以此形式做删除工作

然后将最后一个元素置为null

index的值是lastRet赋值的

因为后续的元素向前移动了,因此cursor也要向前移动一次,即cursor = lastRet,

如果不向前移动会漏掉元素,也就是index+1处的元素会被漏掉 

最重要的是remove()里 进行了modCount++操作

但是迭代器的remove里进行了expectedModCount=modCount; 而集合的remove没有

(一)List子接口

     1.ArrayList :  底层是动态数组,对象存储在连续的位置上

     2. LinkedList底层时双链表的数据结构,对象不存储在连续的空间上,

比较(前提是数据量很大的情况下):

     随机访问 ArrayList 高于 LinkedList ,因为LinkedList要移动指针

     插入和删除 LinkedList高于ArrayList  因为ArrayList要移动数据

      ArrayList 和 LinkedList 两个实现类的常用方法基本相同

 1. 常用方法

1. 添加元素

  • boolean add(E e)作用:向列表末尾添加指定的元素

  • void add(int index, E element)作用:在列表的指定位置添加集合

  • boolean addAll(Collection c ) 作用:将集合c中的所有元素都添加到列表的结尾

  • boolean addAll(int index, Collection c)   作用:将集合c中的所有元素添加到列表的指定位置

public class ArrayLiatTest {
    public static void main(String[] args) {
        ArrayList<Integer> a = new ArrayList<>();
        a.add(1);
        a.add(2);
        System.out.println("集合a"+a);
        //在下标为1处添加索引
        a.add(1,3);
        System.out.println("在下标为1处添加3:"+a);
        ArrayList<Integer> b = new ArrayList<>();
        b.add(4);
        b.add(5);
        System.out.println("集合b"+b);
        a.addAll(b);
        System.out.println("将集合b加到a中:"+a);
        a.addAll(0,b);
        System.out.println("将集合b加到a的下标为0处:"+a);
    }
}

2.获取元素

  • E get(int index)作用:返回列表指定位置的元素

public class GetArrayList {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("A");
        list.add("B");
        list.add("C");
        System.out.println(list);
        String element = list.get(2);
        System.out.println("得到下标为2的元素为:"+element);
    }
}

3.查找元素

  • int indexOf(Object obj)  作用:返回列表中指定元素第一次出现的位置,如果没有该元素,返回-1

  • int lastIndexOf(Object obj)  作用:返回列表中指定元素最后一次出现的位置,如果没有该元素,返回-1

public class findArrayList {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("A");
        System.out.println(list);
        int first = list.indexOf("A");
        System.out.println("A第一次出现的位置:"+first);
        int last = list.lastIndexOf("A");
        System.out.println("A最后一次出现的位置:"+last);
        first = list.indexOf("D");
        System.out.println("D第一次出现的位置:"+first);
        last = list.lastIndexOf("D");
        System.out.println("D最后一次出现的位置:"+last);
    }
}

4. 移除元素

  • E remove(int index)    作用:移除集合中指定(位置)的元素,返回被移除掉的元素对象

  • boolean remove(Object o)    作用:移除集合中 指定元素返回的是  移除元素是否成功

  • boolean isRemove(Object o)   作用:移除集合中指定(位置)的元素,返回移除是否成功

public class RemoveArrayList {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("A");
        list.add("B");
        list.add("C");
        System.out.println("最开始的元素"+list);
        boolean a =list.remove("A");
        System.out.println("删除A元素后"+list);
        System.out.println("移除A是否成功:"+a);

        String s = list.remove(1);
        System.out.println("删除下标为1的元素后"+list);
        System.out.println("移除的元素为:"+s);
    }
}

5.修改元素

  • E set(int index, E element)

       作用:用指定元素替换指定位置上的元素,返回被替换出来的元素对象

public class SetElement {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("apple");
        list.add("banana");
        list.add("orange");
        list.add("apple");
        System.out.println(list);
        String s =  list.set(1, "grape");
        System.out.println("修改下标为1的元素后"+list);
        System.out.println("修改后得到的元素为:"+s);

    }
}

6. 截取子集

  • List subList(int fromIndex, int toIndex)

    作用:截取子集,返回集合中指定的fromIndex 到 toIndex之间部分视图包前不包后

就是指如果将截取的子集位置上的元素改变,那么原来的集合该位置上的元素也会改变

public class SetElement {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("hi1");list.add("hi2");
        list.add("hi3");list.add("hi4");
        System.out.println(list);
        String s =  list.set(1, "hi5");
        System.out.println("修改下标为1的元素后"+list);
        System.out.println("修改后得到的元素为:"+s);
        List<String> subList = list.subList(1,3);
        System.out.println("截取下标为1到3的子集合:"+subList);
        subList.set(0, "pear");
        System.out.println("截取的集合为:"+subList);
        System.out.println("原来的集合:"+list);
    }
}

2. 遍历

3种方法

普通for循环

因为ArrayList 和 LInkedList 都有序 ,存在下标,所以可以用普通for循环遍历。

public class ListTraverse {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("A");
        list.add("B");
        list.add("C");
        System.out.println(list);
        for(int i = 0;i<list.size();i++){
            System.out.println(list.get(i));
        }
    }
}

增强for循环

 for(String s : list){
     System.out.println(s);
 }

迭代器

   Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String element = it.next();
            System.out.println(element);
        }

(二)Queue 子接口

底层数据结构:队列(从一端添加(offer)元素,从另一端取出(poll)元素)

1. 常用方法
  • boolean offer(E e):作用:将一个对象添加到队尾,如果添加成功返回true
  • String poll() 作用:从队首删除并返回这个元素
  • E peek()作用:查看队首的元素
public class QueueTest {
    public static void main(String[] args) {
        Queue<Integer> q = new LinkedList<Integer>();
        q.offer(1);
        q.offer(2);
        q.offer(3);
        System.out.println("集合q: " + q);
        q.poll();
        System.out.println("删除队首元素后:"+q);
        int s = q.peek();
        System.out.println("查看队首元素:"+s);
    }
}
2. 子接口 Deque

Deque是Queue的子接口,定义了所谓的”双端队列”,即从队列的两端分别可以入队(offer)和出队(poll)。同样,LinkedList实现了该接口

  • boolean offerFirst(Element e):从队首入队 
  • boolean  offerLast(ELement e):从队尾入队
  • boolean  pollirst():boolean poll()  :从队首出队 
  • boolean  pollLast():从队尾出队
public class DequeTest {
    public static void main(String[] args) {
        Deque<Integer> deque = new LinkedList<>();
        deque.addFirst(1);
        deque.addFirst(2);
        System.out.println(deque);
        deque.addLast(3);
        deque.addLast(4);
        System.out.println(deque);
        deque.poll();
        System.out.println(deque);
        deque.pollFirst();
        System.out.println(deque);
        deque.pollLast();
        System.out.println(deque);
    }
}

如果将Deque限制为只能一端入队和出队,则可以实现“栈”(Stack)的数据结构,对于栈而言,入栈被称为push,出栈被称为pop。遵循先进后出(FILO)原则

常用方法:

  • push( Element e ) 作用:把元素e放进集合中
  • String pop();  作用 返回被弹出的元素 先入后出
public class QueueDemo03 {
    public static void main(String[] args) {
        Deque<String> stack = new LinkedList<>();

        //从栈的出口进入,对应的方法push,表示把元素推进去
        stack.push("michael");
        stack.push("lucy");
        stack.push("lily");
        stack.push("tom");
        System.out.println(stack);

        //出栈(弹出) 对应的方法pop() 将元素弹出栈结构
        while (stack.size() > 0) {
            String el = stack.pop();
            System.out.println(el);
        }
    }
}

打印也是先进去的最后打印

先进去的是michael 先出来的是tom

(三)Set接口

  1. Set集合中的元素是无序的(取出的顺序与存入的顺序无关

  2. Set集合中的元素不能重复

         ------即不能把同一个东西或者相似的东西两次添加到同一个Set容器中,每次放入时都会进行判断是否存在,如果存在,就不添加。--即不能把同一个东西或者相似的东西两次添加到同一个Set容器中,每次放入时都会进行判断是否存在,如果存在,就不添加。

   - 设计初衷:
        用来存储不重复的元素,元素的顺序是无序(取出的顺序和存入的顺序无关)的
        (一旦存入,在存储结构 里的顺序固定了 和存入先后顺序无关
         也就是打印的顺序是一样的)
   -  set接口里的方法都是Collection接口的方法
   - HashSet: 是实现了Set接口里的最经典的子类型
              -底层的存储方式使用的是Hash算法(哈希表)

去重原理:每添加一个元素,会计算它的哈希值,判断哈希表上的该位置是否有元素

如果有元素,那么调用equals调用它们的属性是否一样。如果一样那么就不能添加,如果不一样就添加进来

(一)HashSet类

遍历

两种方式:因为没有下标,所以不能用普通for循环遍历

增强for循环

迭代器

LinkedHashSet类

是HashSet的子类

LinkedHashSet 集合根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。

LinkedHashSet 性能插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。

LinkedHashSet 不允许集合元素重复。

(二)TreeSet

TreeSet 是 SortedSet 接口的实现类,TreeSet集合的元素是有序的,即内部维护一个二叉树算数的排序方式

TreeSet集合是用来对元素进行排序的,同样他也可以保证元素的唯一。

TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。可以自定义一个比较器

public class SetDemo04 {
    public static void main(String[] args) {

        Set<String> set = new TreeSet<>();// 创建一个空的TreeSet集合
        set.add("a");
        set.add("b");
        set.add("c");
        set.add("d");
        set.add("bob");
        set.add("bab");
        System.out.println(set);
        Comparator c1 = new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        };
        Set<Integer> nums = new TreeSet<>(c1);
        nums.add(1);
        nums.add(20);
        nums.add(4);
        nums.add(3);
        System.out.println(nums);
    }
}

常用方法都是从Collection中继承过来的

二、Map

Map是集合框架中的另一个父接口,它用来保存具有映射(一对一)关系的数据,这样的数据称之为键值对(Key-Value-Pair)。key可以看成是value的索引。特点如下:

  • key和value必须是引用类型的数据

  • 作为key,在Map集合中不允许重复

  • key可以为null

  • key和value之间存在单向一对一关系,通过指定的key总能找到唯一,确定的value

HashMap和TreeMap类实现了Map接口

LinkedHashMap继承了HashMap类

    常用方法:
  • V put();  向集合中添加一个键值对,如果已经存在会用新的值覆盖
  • putIfAbsent()   如果不存在才会增,存在不会覆盖,没有任何效果
public class Method {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("a", 1);
        map.put("b", 2);
        System.out.println(map);
        //覆盖
        map.put("a", 3);
        System.out.println(map);
        //存在不变,不存在覆盖
        map.putIfAbsent("a", 4);
        System.out.println(map);
    }
}

  • remove(K key)  按照键删除键值对
  • remove(K key ,V value)  按照键值对删除 只有当键和值都能够匹配上的时候才删除
  • clear()  清空所有的键值对
  • boolean isEmpty()  判断是否为空
  • boolean containKey(Object key)   判断是否包含key
  • boolean containsValue()  判断是否包含Value
  • int size()  返回集合中键值对的个数
public class MapDemo02 {
    public static void main(String[] args) {
        HashMap<String,String> course = new HashMap<>();
        course.put("王老师","语文");
        course.put("李老师","数学");
        course.put("张老师","化学");
        course.put("赵老师","生物");
        System.out.println(course);

        /**
         *  1. boolean isEmtpy():判断map是否为空
         */

        System.out.println("course是否为空:" + course.isEmpty());

        // 2. containsKey()
        System.out.println("是否包含张老师" + course.containsKey("张老师"));
        //3. containsValue()
        System.out.println("是否包含语文" + course.containsValue("语文"));
        //4. remove()
        course.remove("张老师");
        System.out.println("移除张老师后:"+course);
        //remove(K,V)
        course.remove("赵老师","生物");
        System.out.println("移除赵老师生物后:"+course);
        //5. size()
        System.out.println("course的大小:" + course.size());
        //6. clear() :清空所有的键值对
        course.clear();
        System.out.println("清空后:"+course);
        System.out.println("集合的大小"+course.size());
    }
}

   遍历

三种方式

1. 得到ketSet存到Set集合中,然后遍历key,通过get()方法得到value值

2. 使用entrySet 方法 ,返回entry对象的set集合

Set<Map.Entry<K,V>> set = map.entrysSet;

for(Map.Entry<K,V> entry: set){

      System.out.println( entry);

      entry.getKey();  //Entry类提供的getKey()方法获取键

      entry.getValue(); //Entry类提供的getValue()方法获取值

}

3. 使用values()方法返回所有的 values的集合

public class mapfor {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("apple", 10);
        map.put("banana", 20);
        map.put("orange", 30);
        map.put("grape", 40);

        //得到key的set集合,然后通过get方法拿到value的值
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(key + ":" + map.get(key));
        }

        Set<Map.Entry<String, Integer>> set = map.entrySet();
        for (Map.Entry<String, Integer> entry : set) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }

       for(Integer value:map.values()){
           System.out.println(value);
       }
    }
}

三、排序(Comparable and Comparable)

只有有序的集合才能进行排序,即插入顺序和取出打印顺序一样的集合

1. 实现Comparable接口

2. 定义一个comparator比较器

如果不想修改源码,可以定义一个比较器,指定临时的比较规则

List 案例

package com.se.compare;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import static java.util.Collections.sort;

public class Sort {
    public static void main(String[] args) {
        List<Person> list = new ArrayList<>();
        Person p =new Person("Alice", 25);
        Person p2 =new Person("Bob", 30);
        Person p3 =new Person("Charlie", 20);
        list.add(p);
        list.add(p2);
        list.add(p3);
        Collections.sort(list);
        System.out.println(list);

        //如果此时想升序排序 就可以定义一个比较器
        Comparator<Person> c = new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {
                return p1.getAge() - p2.getAge();
            }
        };
        Collections.sort(list, c);
        System.out.println(list);
    }
}
class Person implements Comparable<Person> {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
    public String toString(){
        return
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    //按照年龄降序排序`
    @Override
    public int compareTo(Person o) {
        return -(this.age - o.getAge());
    }
}

TreeSet案例 

package com.se.compare;


import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;

//年龄降序,年龄相同,工资升序,工资相同 工龄降序
public class mapSort {
    public static void main(String[] args) {
        Set<Employee> set = new TreeSet<>();
        Employee e1 = new Employee("Tom", 25, 5000, 5);
        Employee e2 = new Employee("Jerry", 25, 6000, 4);
        Employee e3 = new Employee("Mike", 20, 4000, 2);
        Employee e4 = new Employee("Lily", 25, 5000, 1);

        set.add(e1);
        set.add(e2);
        set.add(e3);
        set.add(e4);
        for (Employee e : set) {
            System.out.println(e);
        }

    }
}

class Employee implements Comparable<Employee> {
    private String name;
    private int age;
    private double salary;
    private int workAge;

    public Employee(String name, int age, double salary, int workAge) {
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.workAge = workAge;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public double getSalary() {
        return salary;
    }

    public int getWorkAge() {
        return workAge;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age && Double.compare(salary, employee.salary) == 0 && workAge == employee.workAge && Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, salary, workAge);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                ", workAge=" + workAge +
                '}';
    }

    @Override
    public int compareTo(Employee e) {
        if (e.getAge() == this.getAge()) {
            if (e.getSalary() == this.getSalary()) {
                return e.getWorkAge() - this.getWorkAge();
            }
            return (int)(this.getSalary() - e.getSalary());
        }
        return e.getAge() - this.getAge();
    }

}

如果在compareto 方法里面只写this.age-o.age

那么当年龄相同时,不会进入到集合中

package com.se.compare;


import java.util.Comparator;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;

//年龄降序,年龄相同,工资升序,工资相同 工龄降序
public class mapSort {
    public static void main(String[] args) {
        Set<Employee> set = new TreeSet<>();
        Employee e1 = new Employee("Tom", 25, 5000, 5);
        Employee e2 = new Employee("Jerry", 25, 6000, 4);
        Employee e3 = new Employee("Mike", 20, 4000, 2);
        Employee e4 = new Employee("Lily", 25, 5000, 1);

        set.add(e1);
        set.add(e2);
        set.add(e3);
        set.add(e4);
        for (Employee e : set) {
            System.out.println(e);
        }
        
        Comparator<Employee> c = new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                if (o2.getAge() == o1.getAge()) {
                    if (o2.getSalary() == o1.getSalary()) {
                        return o2.getWorkAge() - o1.getWorkAge();
                    }
                    return (int) (o1.getSalary() - o2.getSalary());
                }
                return o2.getAge() - o1.getAge();
            }
        };
        for (Employee e : set) {
            System.out.println(e);
        }

    }
}

class Employee implements Comparable<Employee> {
    private String name;
    private int age;
    private double salary;
    private int workAge;

    public Employee(String name, int age, double salary, int workAge) {
        this.name = name;
        this.age = age;
        this.salary = salary;
        this.workAge = workAge;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public double getSalary() {
        return salary;
    }

    public int getWorkAge() {
        return workAge;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age && Double.compare(salary, employee.salary) == 0 && workAge == employee.workAge && Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, salary, workAge);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                ", workAge=" + workAge +
                '}';
    }

    @Override
    public int compareTo(Employee e) {

        return e.getAge() - this.getAge();
    }

}

四、比较

1.底层

ArrayList : 动态数组+各种方法

LinkedList : 动态链表+各种方法

HashSet: 底层是HashMap 的put方法 只不过只用了HashMap的key

HashMap: 底层是数组+ 单向链表+红黑树

LinkedHashMap:底层是数组+双向链表+红黑树

2.有序or无序

List集合都是有序的

HashSet无序

LinkedHashSet 和 TreeSet有序

HashMap无序,LinkedHashMap和TreeMap有序

五、Collections类

Collections 是一个操作 Set、List 和 Map 等集合的工具类,提供了大量方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法

1. 排序操作(只能对实现List接口的类)

  • reverse(List):反转 List 中元素的顺序 

  • shuffle(List):对 List 集合元素进行随机排序

  • sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序

  • sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序

  • swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换

public class Sort {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(3);
        list.add(1);
        list.add(4);
        list.add(2);
        list.add(5);
        System.out.println(list);
        Collections.sort(list);
        System.out.println("默认排序后"+list);
        Collections.reverse(list);
        System.out.println("反转后"+list);
        Collections.shuffle(list);
        System.out.println("洗牌后"+list);

        Comparator<Integer> c = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        };

        Collections.sort(list, c);
        System.out.println("自定义排序后"+list);

        Collections.swap(list, 0, 1);
        System.out.println("交换后0位置和1位置后"+list);
    }
}

2. 查找、替换

  • Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素

  • Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大位置上的元素

  • Object min(Collection) 根据元素的自然顺序,返回给定集合中的最小元素

  • Object min(Collection,Comparator)  根据 Comparator 指定的顺序,返回给定集合中的最小位置上的元素

  • int frequency(Collection,Object):返回指定集合中指定元素的出现次数

  • boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值

public class Find {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(3);
        list.add(1);
        list.add(4);
        list.add(2);
        list.add(5);
        list.add(5);
        System.out.println(list);
        int max = Collections.max(list);
        System.out.println("集合中最大的元素: " + max);
        Comparator<Integer> c = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        };
        Collections.sort(list, c);
        System.out.println(list);
        max = Collections.max(list, c);
        System.out.println("排序后最后一个位置上的元素" + max);
        int min = Collections.min(list);
        System.out.println("集合中最小的元素: " + min);
        min = Collections.min(list, c);
        System.out.println("排序后第一个位置上的元素" + min);

        int frequency = Collections.frequency(list, 5);
        System.out.println("集合中元素5出现的次数: " + frequency);

        System.out.println(list);
        boolean replaceAll = Collections.replaceAll(list,5,6);
        System.out.println("替换是否成功: "+replaceAll);
        System.out.println("替换后的集合: "+list);
    }
}

3.集合转数组

  集合转数组
  Object[] toArray()
    作用将集合转成Object数组,一旦想要使用数组中元素的子集的方法和属性,还需要强转
 
  T[] toArray(T[] a)
  作用:只需要传入一个元素类型的数组对象就可以返回元素类型的数组
public class CollectionDemo02 {
    public static void main(String[] args) {
     
        List<String> names = new ArrayList<String>();
        names.add("John");
        names.add("Jane");
        names.add("Bob");


        //第一种 得到的是Object类型的数组
        Object[] arr1 = names.toArray();
        Object o = arr1[1];
        if(o instanceof String){
            String s = (String)o;
            char c = s.charAt(1);
            System.out.println(c);
        }


        //第二种 定义一个String 类型的数组传入
        String[] arr = new String[0];
        String[] array = names.toArray(arr);
        System.out.println(array.length);
        System.out.println(Arrays.toString(array));
        
        String s1 = array[0];
        System.out.println(s1);
        boolean b =s1.endsWith("hn");
        System.out.println("是否以hn结尾:"+b);
    }
}

4.数组转集合

  数组转集合
   1. 数组转成的集合对象 不可以改变集合的长度
   2. 如果想要进行增删操作,可以将转成的元素放入一个新的

public class CollectionDemo03 {
    public static void main(String[] args) {
        String[] names = new String[5];
        names[0] = "Michael";
        names[1] = "Jane";
        names[2] = "Doe";
        names[3] = "Mike";
        names[4] = "John";

        List<String> list = Arrays.asList(names);
        System.out.println(list);
        System.out.println(list.size());

        list.set(1, "Jack");
        System.out.println(list);
        //添加和移除有异常,因为会修改长度,
//        list.add("Tom");
//        list.remove(2);

        /**
         *  向集合中添加新元素 “张三和李四”
         */
        List<String> newList = new ArrayList<>();
        newList.addAll(list);
        System.out.println("新的集合: "+newList);
        newList.add("张三");
        newList.add("李四");
        System.out.println("新的集合: "+newList);
        String zhangsan = newList.get(newList.size()-2);
        String str1 = newList.set(0, zhangsan);
        newList.set(newList.size()-2, str1);
        System.out.println("新的集合: "+newList);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值