常用集合类:

1、iterator便利:

  所有的集合父类collection实现了Iterable。该集合里有三个方法  其中一个重要的方法 iterator()方法。在所有集合的实现类重写了这个方法。

 ArrayList list= new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
       
        Integer integer = new Integer(2);
        list.remove(integer);
        
        Iterator iterator = list.iterator();
//        ListIterator iterator = list.listIterator();
        while(iterator.hasNext()){
            Object o = iterator.next();
            if(o.equals(1)){
                iterator.remove(); //此处遍历器已经不支持删除操作  也不zhichilist.remove(o)  所以用list。listIterator()
            }
            System.out.println(o);
        }
    }

 但是通过便利删除list.remove()会数据上移,造成游标的混乱判断。所以会报异常,那么可以用通过iterator 的remove方法实现,通过源码可以看到此处抛出了一个异常,不支持这个方法。

那么可以通过arraylIst的listIterator()来进行便利实现。

在使用iterator进行迭代的过程中如果删除其中的某个元素会报错,并发操作异常,因此
*       如果遍历的同时需要修改元素,建议使用listIterator(),
*   ListIterator迭代器提供了向前和向后两种遍历的方式
*       始终是通过cursor和lastret的指针来获取元素值及向下的遍历索引
*       当使用向前遍历的时候必须要保证指针在迭代器的结果,否则无法获取结果值
Iterator iterator = list.iterator();
//        ListIterator iterator = list.listIterator();
        while(iterator.hasNext()){
            Object o = iterator.next();
            if(o.equals(1)){
                iterator.remove();
            }
            System.out.println(o);
        }
//        System.out.println("-------------");
//        while (iterator.hasPrevious()){
//            System.out.println(iterator.previous());
//        }
//        for(Object i : list){
//            System.out.println(i);
//        }

如上图:此时向前便利,向后便利。如果指针在最后面获取不到元素。

2、vector也是list的实现类,他是线程安全的。

3、list的实现类主要有arrayList和LinkList两类。arraylist底层是数组实现,那么查找会快一些。linkList底层是链表实现。删除和插入快一些。修改的查询话都需要逐个便利元素。

4、以后尽量减少使用增强for循环,不变与对数据的操作。

5、摘要

ListIterator的作用解决并发操作异常
▪ 在迭代时,丌可能通过集合对象的方法(al.add(?))操作集合中的元素,
▪ 会发生并发修改异常。
▪ 所以,在迭代时只能通过迭代器的方法操作元素,但是Iterator的方法
▪ 是有限的,只能进行判断(hasNext),取出(next),删除(remove)的操作,
▪ 如果想要在迭代的过程中进行向集合中添加,修改元素等就需要使用
▪ ListIterator接口中的方法
ListIterator li=al.listIterator();
while(li.hasNext()){
 Object obj=li.next();
 if ("java2".equals(obj)) {
 li.add("java9994");
 li.set("java002");
 }
}

6、迭代器会维持到方法体结束,消耗内存空间。迭代器从创建一开始,一直到方法结束。所以建议用第二种方法。写在for 循环里作用域是这个循环内。

  建议用第二中反方法,放到for循环里实现。

二、set set是无序的且不重复的集合。常见的实现有hashSet和TreeSet和LinkHashSet。

  通过底层代码,我们可以看到hashSet就是hashMap。是通过计算添加数据的hashcode值。在比较equas方法,通过算法去重,数据散列,实现无序且不可重复的集合。好的算法可以减少数据的散列。

   TreeSet可以确保数据的一致性,底层是TreeMap 红黑树。查询速度快一些。红黑树与平衡树最大的区别就是减少了自旋所带来的性能消耗,提升了插入效率。

  1、hashSet和TreeSet的区别:

Set接口中的实现类
▪HashSet:采用Hashtable哈希表存储结构
–优点:添加速度快,查询速度快,删除速度快
–缺点:无序
–LinkedHashSet
▪ 采用哈希表存储结构,同时使用链表维护次序
▪有序(添加顺序)
▪TreeSet
–采用二叉树(红黑树)的存储结构
–优点:有序(排序后的升序)查询速度比List快
–缺点:查询速度没有HashSet快

  不同点:treeSet添加数据的时候,必须要添加同一类型,并且有可以排序的数据比较。

  

 

 

 内部比较器:实现compareable接口。

  

 

 

 外部比较器的使用:

  在当前类中实现 Comparator接口,并重写了 compare方法。然后把该比较器传入到集合中。

public class SetDemo implements Comparator<Person> {
    public static void main(String[] args) {

        TreeSet treeSet = new TreeSet(new SetDemo());
        treeSet.add(new Person("lisi",15));
        treeSet.add(new Person("wangwu",13));
        treeSet.add(new Person("maliu",12));
        treeSet.add(new Person("zhangsan",19));
        treeSet.add(new Person("zhangsan",12));
        System.out.println(treeSet);


    }

    @Override
    public int compare(Person o1, Person o2) {
        if(o1.getAge()>o2.getAge()){
            return -1;
        }else if(o1.getAge() < o2.getAge()){
            return 1;
        }else{
            return 0;
        }
    }

set内容总结:

*   1、set中存放的是无序,唯一的数据
*   2、set不可以通过下标获取对应位置的元素的值,因为无序的特点
*   3、使用treeset底层的实现是treemap,利用红黑树来进行实现
*   4、设置元素的时候,如果是自定义对象,会查找对象中的equals和hashcode的方法,如果没有,比较的是地址
*   5、树中的元素是要默认进行排序操作的,如果是基本数据类型,自动比较,如果是引用类型的话,需要自定义比较器
*       比较器分类:
*         内部比较器
*               定义在元素的类中,通过实现comparable接口来进行实现
*         外部比较器
*               定义在当前类中,通过实现comparator接口来实现,但是要将该比较器传递到集合中
*         注意:外部比较器可以定义成一个工具类,此时所有需要比较的规则如果一致的话,可以复用,而
*               内部比较器只有在存储当前对象的时候才可以使用
*               如果两者同时存在,使用外部比较器
*               当使用比较器的时候,不会调用equals方法

  当使用比较器的时候,如果比较的值相当,那么会进行去重操作。

 三、泛型

  泛型的使用: 

 泛型的高阶应用:
 *      1、泛型类
 *          在定义类的时候在类名的后面添加<E,K,V,A,B>,起到占位的作用,类中的方法的返回值类型和属性的类型都可以使用
 *      2、泛型接口
 *          在定义接口的时候,在接口的名称后添加<E,K,V,A,B>,
 *          1、子类在进行实现的时候,可以不填写泛型的类型,此时在创建具体的子类对象的时候才决定使用什么类型
 *          2、子类在实现泛型接口的时候,只在实现父类的接口的时候指定父类的泛型类型即可,此时,测试方法中的泛型类型必须要跟子类保持一致
 *      3、泛型方法
 *          在定义方法的时候,指定方法的返回值和参数是自定义的占位符,可以是类名中的T,也可以是自定义的Q,只不过在使用Q的时候需要使用<
 *          Q>定义在返回值的前面
 *      4、泛型的上限(工作中不用)
 *          如果父类确定了,所有的子类都可以直接使用
 *      5、泛型的下限(工作中不用)
 *          如果子类确定了,子类的所有父类都可以直接传递参数使用
 *

   1、定义泛型类 默认E代表element  k是key  v是value

public class FanXingClass<A> {

    private int id;
    private A a;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }

    public void show(){
        System.out.println("id : "+id+" ,A : "+a);
    }

    public A get(){
        return a;
    }

    public void set(A a){
        System.out.println("执行set方法:" + a);
    }

    2、定义泛型的接口实现:

package _05_第五章泛型.E202_05_02_数据相加;
public class Test {
    public static void main(String[] args) {
        Point p1 = new Point(1,1);
        Point p2 = new Point(3,2);
 
        Circle circle = new Circle(p1,2);
        Circle circle2 = new Circle(p2,3);
        System.out.printf("两个 圆 相加结果:\n");
        System.out.println(circle2.add(circle));
 
        Complex complex = new Complex(1,1);
        Complex complex2 = new Complex(2,2);
        System.out.printf("两个 复数 相加结果:\n");
        complex2.Print(complex2.add(complex));
    }
}
 
package _05_第五章泛型.E202_05_02_数据相加;
public interface Add<T> {
    public T add(T t);
}
 
package _05_第五章泛型.E202_05_02_数据相加;
public class Circle implements Add<Circle> {
    private Point p;//圆心
    private float r;//半径
 
    public Circle(Point p, float r) {
        this.p = p;
        this.r = r;
    }
    public Circle add(Circle circle2){
        circle2.p =this.p.add(circle2.p);
        circle2.r =this.r + circle2.r ;
        return circle2;
    }
    @Override
    public String toString() {
        return String.format("圆心:(%f,%f)  半径:%f",p.x,p.y,r);
    }
}

    3、泛型的方法比较特殊,如果没有返回值,那么需要添加哥泛型。

public class FanXingMethod<T> {
    private T t;
    public T getT() {
        return t;
    }
    public void setT(T t) {
        this.t = t;
    }
    public <Q> void show(Q q){
        System.out.println(q);
        System.out.println(t);
    }

三、Map类 

1、hashmap跟hashtable的区别:

1、hashmap线程不安全,效率比较高,hashtable线程安全,效率低
2、hashmap中key和value都可以为空,hashtable不允许为空

map存储的是k-v键值对映射的数据
 *      实现子类:
 *          HashMap:数据+链表(1.7) 数组+链表+红黑树(1.8*          LinkedHashMap:链表
 *          TreeMap:红黑树

2、常见的hashMap便利操作

 //遍历操作
        Set<String> keys = map.keySet();
        for(String key:keys){
            System.out.println(key+"="+map.get(key));
        }

        //只能获取对应的value值,不能根据value来获取key
        Collection<Integer> values = map.values();
        for (Integer i:values){
            System.out.println(i);
        }

        //迭代器
        Set<String> keys2 = map.keySet();
        Iterator<String> iterator = keys2.iterator();
        while(iterator.hasNext()){
            String key = iterator.next();
            System.out.println(key+"="+map.get(key));
        }
        //Map.entry
        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator1 = entries.iterator();
        while (iterator1.hasNext()){
            Map.Entry<String, Integer> next = iterator1.next();
            System.out.println(next.getKey()+"--"+next.getValue());
        }

Map.ENtry格式类型:有key和value和hashCode值 有指针

  

  在java8以后hashMap是什么时候使用红黑树的?在大于8的时候。

  hashMap初始化的数组长度为2的N次幂。这样便于位移运算扩容。

 

posted @ 2022-04-05 22:13  Jerry&Ming  阅读(74)  评论(0)    收藏  举报