【数据结构】集合框架(泛型、包装类、集合框架)

目录

一、泛型

二、包装类

三、集合框架

1、Collection接口

2、List接口

3、ArrayList和LInkedList类

4、遍历和Iterator

总结


一、泛型

        泛型即通用类型。为了我们方便使用过程中不用刻意去局限于某种具体的数据类型。java语言提供了这种特性。泛型在Java中的明显的标识就是一组尖括号   " < ... > "。对于泛型来说,类型是在具体使用该类的时候而明确的。基本使用如下

package genericity;

public class Demo<E> {
    //在本类中可以把E当作一种类型
    private E[] array;
    private int size;

    public Demo(){
        //泛型不允许定义数组;
        array=(E[])new Object[10];
        size=0;
    }
    public void add(E e){
        array[size]=e;
        size++;
    }
}

使用Demo时,我们才明确具体的类型

package genericity;
import java.util.Random;
public class Use {
    public static void main(String[] args) {
        //用String赋值给E
        Demo<String> demo=new Demo<>();
        demo.add("libowen");
        //demo.add(1);
        Demo<Random> demo1=new Demo<>();
        demo1.add(new Random());
    }
}

泛型的擦除:

        在没有泛型之前,我们使用object类来做类似的事情。但是这种方式是存在一定问题的(此处不讨论),于是泛型的出现有其必要性。

        但是为了保证兼容性,Java的泛型只存在于编译阶段,即泛型擦除。也就是说在在.java文件中是存在的,但是经过编译操作,class文件中就不存在这个东西了。

注意:泛型和数组都很特殊,其中存在一些细小的规则。至于泛型中的上界下界问题目前只需能够看懂即可。

二、包装类

        泛型的原理是利用object类可以指向任意的对象类型,但是有些类型不是对象类型怎么办?

比如我们的8大基础类型,他们并不属于对象类型。

        Java专门为8种基本类型定义了各自对应的类类型。如下所示:

        Java为我们提供了便利,没有歧义时会自动装箱和自动拆箱。并且包装类为我们提供了一些相应的静态方法或属性来使用。如Integer.sum()、Integer.max()、Character.isLetter()、Character.isDigit()具体的方法可以自己查阅。

三、集合框架

        Java 集合框架(Java Collection Framework),又被称为容器 container ,是定义在 java.util 包下的一组接口 interfaces 和其实现类 classes 。其主要表现为将多个元素 element 置于一个单元中,用于对这些元素进行快速、便捷的存储 store 、检索 retrieve 、管理 manipulate ,即平时我们俗称的增删查改 CRUD 。

        

        从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、HashMap等等。

1、Collection接口

        我们先简单的介绍以下Iterable——>collection——>List——>ArrayList和LinkedList这条线。首先,collection接口继承自Iterable接口。其中Collection接口是不一定具有线性结构的特点的。collection中的常见方法:

int size()返回容器中元素的个数
boolean isEmpty()size()==0,注意不要和null弄混了
boolean contains(Object o)遍历所有元素,和o进行相等性比较,会调用对象的equals方法,就可能要重写equals方法。

boolean add(E e)

添加元素,放入可能失败
boolean remove(Object o)

要判断相等性,会用到equals方法

只会删除一个,并不保证是哪一个

boolean addAll(Collection c)将c中的元素放入当前容器中
void clear()清除容器

2、List接口

List继承自Collection接口。此时元素具有顺序结构了,自然也就多出了相应的功能

boolean add(E e)

尾插,不会失败
boolean add(int index,E e)插到指定下标处
boolean remove(Object o)

明确删除第一个遇到的和o相等的元素

boolean addAll(Collection c)将c中的元素按照一定顺序放入当前容器中
sort(Comparator<E> c)传入一个比较器,按其规则进行排序
E get(int index)返回index处的元素
E set(int index, E e )将index处的元素进行修改
int indexOf(E e)从前往后第一个和e相等元素(equals)的下标
int lastIndexOf(E e)从后往前
List<E> subList(int f,int t)将 [ i , t )截取为一个新的线性结构并返回

3、ArrayList和LInkedList类

ArrayList和LInkedList都继承自List。我们在之前了解过相关的操作。

注意:

        ArrayList的subList实现返回的并不是一个完全独立的List。属于浅拷贝,如果我们进行改动会造成影响。

        List<Integer> list = new ArrayList<>(10)中传入的参数10表示的是initialcapcity,并不是size.此时list中没有元素。不注意可能会异常。

ArrayList和数组的转换:

数组——>ArrayList:通过Arrays.asList(array),其中array是包装类的数组,不能是基础类型。或者直接传入字面量

ArrayList——>数组:通过list.toArray()方法,如果不传入参数的话就会返回Object 数组,所以我们可以传入 new Integer[0] 表示我们的类型是Integer类型,这样就会得到Integer[ ]数组。

Vector & ArrayList 的主要区别
1) 同步性:Vector是线程安全的,也就是说是同步的 ,而ArrayList 是线程序不安全的,不是同步的 数2。
2)数据增长:当需要增长时,Vector默认增长为原来一倍 ,而ArrayList却是原来的50%  ,这样,ArrayList就有利于节约内存空间。
      如果涉及到堆栈,队列等操作,应该考虑用Vector,如果需要快速随机访问元素,应该使用ArrayList 。

        至于LinkedList我们之前了解过,此处不再赘述。

4、遍历和Iterator

        我们以前的遍历方式都是基于下标索引的for循环来实现的。如果没有下标支持,这种方法就不再适用。

        下图为Iterator接口的说明。

于是我们可以采用这样的遍历方式

    public static void main(String[] args) {
//        List<Integer> list = new ArrayList<>(Arrays.asList(1, 5, 2, 9));
        Collection<Integer> list = new HashSet<>(Arrays.asList(1, 5, 2, 9));

        // 没有下标支持,这种遍历方式无法使用
//        for (int i = 0; i < list.size(); i++) {
//            System.out.println(list.get(i));    // 不再成立
//        }

        // x 指向了迭代器对象
        Iterator<Integer> x = list.iterator();
        while (x.hasNext()) {   // x.hasNext()    元素的个数 + 1
            System.out.println(x.next());        // x.next() 元素的个数
        }

        //于是有了这种增强型的for循环
        for (Integer integer : list) {
            System.out.println(integer);
        }

         如果我们在循环中调remove(),我们在使用for循环时就有可能出错。所以尽量不要在遍历中进行remove操作,但是我们可以使用iterator来完成这一操作,这也是官方推荐方法。我们可以看下面这道题。

        假设num已经被创建为一个ArrayList对象,并且最初包含以下整数值:[0,0,4,2,5,0,3,0]。执行下面的方法numQuest(),最终的输出结果是什么?

/*
假设num已经被创建为一个ArrayList对象,并且最初包含以下整数值:
[0,0,4,2,5,0,3,0]。执行下面的方法numQuest(),最终的输出结果是什么?
*/
private List<Integer> nums;
 
//precondition: nums.size() > 0
//nums contains Integer objects
public void numQuest() {
    int k = 0;
    Integer zero = new Integer(0);
    while (k < nums.size()) {
        if (nums.get(k).equals(zero))
            nums.remove(k);
        k++;
    }
}

分析:首先0号下标元素等于0,所以删除。变成[0,4,2,5,0,3,0]。然后新的list的一号下标不为零,所以没变化。以此类推,直到4的时候删除变成[0,4,2,5,3,0] 。然后再删除最后一个0.所以结果就是[0,4,5,2,3]。

总结

        后续就开始了数据结构部分的总结,会逐步对该方面的知识进行查漏补缺。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值