Java中集合章节细分总结

Java的集合是一个非常庞大的体系,在初学Java时很难弄清楚具体的结构,这里对它的体系从几条不同的路径进行一下梳理,其中有较多不常用的细碎分支没有加入,希望最后能有一个简单清晰的框架结构,Java的集合框架主要包括两种类型的容器,即collection集合和map键值对。先从collection集合开始:
这里写图片描述

上图是对collection集合结构的框架简单分类,可以看出它主要分为List ,Set,Queue三个接口,具体他们的API.

从API体系图中可以清晰的看到集合的体系,在我们向集合中添加元素时注意他有一个操作,基本数据类型的自动装箱。

public class TextCase01 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        c.add(1);//自动装箱

这里c.add的参数类型为Object,而输入的1为基本数据类型的int值,这里自动转换为Integer的包装类型,即为自动装箱。

我们将类加入一个容器中时,经常会设置自己的比较逻辑,例如:

public class TextCase02 {
    public static void main(String[] args) {
        ArrayList stus=new ArrayList();
        Stu s1=new Stu("Tom", 1);
        Stu s2=new Stu("jack",2);
        stus.add(s1);
        stus.add(s2);
        Stu s3=new Stu("Tom",1);
        System.out.println(stus.contains(s3));
    }
}

这里直接比较时是无论如何都不会相等的,因为他比较的是地址,不可能相等,所以我们需要加入自己的比较逻辑就是重写equals方法,我们区分什么时候重写方法在我的理解里有三点,一般来说,如果你要吧一个类放入一个容器,一般需要重写他的equals方法用以确认存的是值而不是不能用来比较的地址,如果存入的容器是队列,还需要重写他的hashcode方法,要是存入有序的容器,还需要重写compare to方法。假如不重写equals方法会造成contains,indexof等方法的失灵。

下面为重写equals方法来定义它的比较逻辑:

@Override
public boolean equals(Object o){
    Stu s1=this;
    Stu s2=(Stu)o;
    if(s1.id==s2.id)return true;
    else return false;
}

在上面的比较中也可以看出,在集合中,基本数据类型和包装类传递的是值,引用类型传递的是地址。

在集合容器中为什么一般不使用for循环来遍历数组:

List list=new ArrayList();
for(int i=0;i<10;i++){
    list.add();//创建一个大小为10的容器;
}
System.out.println(list);
for(int a=0;a<list.size();i++){
    list.remove;//逐个删除list中的元素;
}
System.out.println(list);

执行结果我们会发现结果为[1,3,5,7,9],就是进行了隔位删除,产生的原因就是元素个数每次循环减一造成的,要解决这个问题我们可以采取逆序删除的方法,也就是倒着删除,但无论如何这都不是优秀的解决办法,也难免会造成错误。这里同样不可以使用foreach循环解决,因为系统会报异常,正确的循环方法是使用迭代器。下面使用迭代器:

Iterator it= list.Iterator();
while(list.hasnext()){
    Integer e=(Integer)it.next();
    System.out.println(e)
}

使用迭代器可以正确的打印数组元素。使用it.remove()也可以正确的清空数组。

应该注意的一点是在list列表下提供了一个可供双向循环的迭代器,list.listIterator();这里我们将上面的列表数组再进行反向的输出:

ListIterator it= list.ListIterator();
while(it.hasPrevious()){
    Integer e=(Integer)it.previous();
    System.out.println(e);
}

这样可以正确的输出数据,也是推荐的方法。
ArrayList和LinkedList的能效问题:
首先,ArrayList的默认的Capacity大小为10。因为ArrayList的底层是数组,所以要想提高能效,可以直接在容量大小上赋初值,这样可以减少在扩容上的能耗。ArrayList的优势是它底层数组,所以乱序访问速度快,LinkedList的优势是双端链表,动态追加效率高。
这里做一个for循环验证一下:

 public static void main(String[] args) {
        int size=200000;
        LinkedList link=new LinkedList();
        ArrayList array=new ArrayList();
        long start=System.currentTimeMillis();
        for (int i = 0; i <size ; i++) {
            link.add(0,new Object());

        }
        long end=System.currentTimeMillis();
        System.out.println(end-start);
        start=System.currentTimeMillis();
        for (int i = 0; i <size ; i++) {
            array.add(0,new Object());
        }
        end=System.currentTimeMillis();
        System.out.println(end-start);
        }

若将上面的循环输入改为随机数Random,将随机数加入数组随机访问,则会发现ArrayList速度会快非常的多,得出的结果可以看出LinkedList速度明显优于ArrayList,因为后者要进行移位的操作。可以得出一个结论,ArrayList乱序访问快,LinkedList乱序删除快。

接下来是集合中Set接口,Set是一个可迭代的无序不可重复的接口,他的常用实现类就是HashSet(底层实现为map的key,个人理解为key所以不可重复,以后假如有新的认知会来填坑。。),通常我们可以利用他不可重复的特点进行列表去重功能,比循环实现容易的多:

Set set=new HashSet(list);//例子

然后使用set来输出就可以实现。
HashSet和TreeSet的区别是后者的输出是有序的。
HashSet不支持作比较排序,TreeSet支持(重写Compare To的方法)。
数组转为定量列表(大小不再可变的列表)
我们可以通过数组转换为列表,但转成的列表不再支持.add操作:

String[]str={"a","b","c"};
List<String> strs=Arrays.aslist(str);
Strs.add("d");
System.out.println(strs)

这里会报错,系统报不允许二次操作的异常,所以数组转成的列表不允许二次扩容的操作。
同样列表也可以转换成数组:
list.toArray()–>Object[] ;转换成的是一个Object类的数组。
Map
map是做缓存,和临时数据存储最好的接口。

以上就是集合章节的知识点简单总结,还有不少细碎的内容比如compare逻辑等以后再写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值