美文网首页
Java之集合框架和泛型

Java之集合框架和泛型

作者: 如果仲有听日 | 来源:发表于2018-08-06 15:31 被阅读0次

    1. 集合介绍

    集合是java中提供的一种容器,可以用来存储多个数据。由java基础语法中得知,如果数据多了,可以使用数组或者ArrayList集合来存放。

    数组和集合的区别:

        数组的长度是固定的,集合的长度是可变的

        集合中存储的元素必须是引用类型

    集合学习的目标:

        集合本身是一个存储的容器:

            必须能用集合存储对象

            能够增加元素、遍历集合

            能够掌握不同集合的特性

    2. 回顾ArrayList集合

    ArrayList比数组的好处是,存储的元素长度可变。

    ArrayList原则上不存储基本类型,如果是基本类型,是自动装箱存储。

    2.1 对基本类型的操作

    public static void addShowArrList() {

        ArrayListarr = new ArrayList();

        arr.add(11); arr.add(22);

        arr.add(33); arr.add(44);

        arr.add(55); arr.add(66);

        for(int i = 0; i < arr.size(); i++) {

            System.out.println(arr.get(i));

        }

        arr.remove(2);

        for(int i = 0; i < arr.size(); i++) {

            System.out.println(arr.get(i));

        }

    }

    2.2 对引用类型的操作

    定义一个Persion类:

    public class Person {

        private String name;

        private int age;


        public Person() {

        }


        public Person(String name, int age) {

            Super();

            this.name = name;

            this.age = age;

        }

        public String getName() {

            return name;

        }

        public void setName(String name) {

            this.name = name;

        }

        public int getAge() {

            return age;

        }

        public void setAge(int age) {

            this.age = age;

        }

        public String toString() {

            return "Person [name=" + name + ", age=" + age + "]";

        }

    }

    测试代码:

    public static void addShowArrList2() {

        ArrayListarrPerson = new ArrayList();

        arrPerson.add(new Person("aaa", 20));

        arrPerson.add(new Person("bbb", 25));

        arrPerson.add(new Person("ccc", 30));

        for (int i = 0; i < arrPerson.size(); i++) {

            System.out.println(arrPerson.get(i)); //这里因为Person中重写了toString方法,所以不是打印对象地址

        }

    }

    3. 集合的继承关系

    查阅API手册,发现ArrayList类它继承了抽象类AbstractList,同时实现接口List,而List接口又继承了Collection接口。所以Collection接口为最顶层的集合接口了

    interface List extends Collection{

    }

    public class ArrayList extends AbstractList implements List{

    }

    根据源码片段,说明使用ArrayList类时,该类已经把所有抽象方法进行了重写。那么,实现Collection接口的所有子类都会进行方法重写。

        Collection接口常用的子接口有:List接口、Set接口

        List接口常用的子类有:ArrayList类、LinkedList类

        Set接口常用的子类有:HashSet类、LinkedHashSet类

    Collection接口是集合中的顶层接口,它中定义的所有功能子类都可以使用。

    Collection表示一组对象,这些对象也称为Collection的元素。

        List派系的Collection允许有重复的元素,而Set派系的则不允许有重复元素。

        List派系的Collection是有序的,而Set派系的则是无序的集合


    4. 集合Collection

    4.1 Collection的add, clear方法

    add, clear是Collection类的抽象方法,ArrayList最终将他们实现了,用ArrayList举例

    Collection接口中的方法是集合中所有实现类必须拥有的方法

        List extends Collection

        ArrayList implements List

    add方法向集合添加元素;clear方法清空集合,但是不会删掉集合

    4.2 contains、size方法

    private static void testFunc2() {

        Collectioncoll = new ArrayList();

        coll.add("abc");

        coll.add("def");

        coll.add("ghi");

        System.out.println(coll);

        System.out.println(coll.contains("def"));

        System.out.println(coll.contains("acb"));

        System.out.println(coll.size());

    }

    4.3 引申获取长度的方式

        Java中获取长度的三种方式,都返回int型:

            数组.length

            字符串.length()

            集合.size()

    private static void testFunc3() {

        int[] arr = new int[3];

        System.out.println(arr.length);

        String str = "kasdlfjklsdfj";

        System.out.println(str.length());

        Collectioncoll = new ArrayList();

        coll.add("abc");

        coll.add("def");

        coll.add("ghi");

        System.out.println(coll);

        System.out.println(coll.size());

    }

    4.3 toArray方法

    把集合转成数组, 返回是一个存储对象的数组

    private static void testFunc3() {

        Collectioncoll = new ArrayList();

        coll.add("abc");

        coll.add("def");

        coll.add("ghi");

        System.out.println(coll);

        Object[] obj = coll.toArray();

        for(int i = 0; i < obj.length; i++) {

        System.out.println(obj[i]);

        }

    }

    将集合转为数组,这样数组中的集合信息就不能被修改

    4.4 remove方法

    删除集合中的指定参数

    private static void testFunc4() {

        Collectioncoll = new ArrayList();

        coll.add("abc");

        coll.add("def");

        coll.add("ghi");

        System.out.println(coll);

        

        System.out.println(coll.remove("def"));

        System.out.println(coll);

    }

    特别注意:因为ArrayList类是List派系的,是允许有重复元素的,在remove的时候实际上会删除第一个集合中的元素

    5. Iterator接口:迭代器,获取集合元素

    由于Java中有多种集合,它们在存储元素时,采用的存储方式不同,我们要取出这些集合中的元素,可通过一种通用的获取方式来完成。

    屏蔽了不同集合获取元素的不同

    5.1 Iterator实现原理

    迭代器的运用,使用了面向接口的编程思想:

    Iterator是一个接口,使用它必须找到实现类

    在Collection接口中有一个iterator方法, 返回Iterator:Iterator<E>iterator()

    子类ArrayList实现了iterator方法

    ArrayList的iterator()方法,返回的是是Iterator接口的实现类的对象

    Iterator it = array.iterator(), it就是Iterator接口的实现类,是由ArrayList对象array的iterator方法返回的

    5.2 Iterator代码实现

    引申1:如果将ArrayList改为HashSet,意思为使用HashSet集合来添加元素,使用Iterator取出HashSet中的元素。取出时,由于HashSet是Set派系的,Set派系是无须集合,所以Iterator取出时是无序的,且在添加元素时是不能重复的:

    引申2:使用for循环也能使用迭代器

        使用for的唯一好处是由于it是在for中定义的,因此退出for之后,it的存储空间立即被释放,比while节约空间

    for(Iterator it = coll.iterator(); it.hasNext(); ) {

        System.out.println(it.next());

    }

    5.3 Iterator执行过程

    5.4 集合迭代中的转型(不建议这样使用,尽量使用泛型)

    集合可以存任意类型的对象

    集合中,不指定存储的数据类型,因此它什么都可以存

    特别注意:如果要使用默认类型的特有方法,必须进行向下转型

    6. 增强型for循环

    参考:https://www.jianshu.com/p/856ec374ff4e

    也是三种遍历数组的方式之一

    从JDK1.5开始Collection强行继承了Iterable接口,只有一个目的,就是要让集合使用foreach方法

    6.1 foreach遍历数组

    优势:简化代码,方便遍历容器

    劣势:int a只是一个变量,arr中的元素赋值给a,arr内存中的数据无法被改变

    6.2 foreach遍历集合

    Person类:

    需要导包:导包外的包中的Person类

    7. 泛型

    7.1 泛型概述

    在5.4中,由于定义集合Collection时没有声明元素类型,因此同一个集合中可以add任何类型的数据,虽然遍历时打印元素不会出现问题,但要使用到强转类型时就会报错:Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

    在JDK1.5开始就引入了泛型这种安全机制,保证程序的安全性

    泛型:指明了集合中存储的数据类型,用一对<>表明:<数据类型>

    这样,如果添加了非泛型的数据类型,编译器是会报错的

    有了泛型,再使用泛型数据类型的特有方法时,也不需要进行类型强转了

    引申:

    JAVA的泛型是伪泛型,使用了泛型<数据类型>只是针对编译器生效。在编译生成的class文件中,其实是没有泛型的表现的(可以通过java反编译成源码查看,反编译出来的代码没有泛型),但这样也足够安全了。

    据说C++的泛型是真泛型

    7.2 带有泛型的类

    使用过的ArrayList是我们最熟悉的带有泛型的类

        public class ArrayList<E>

    其中E是Element的简写,理解为一个变量类型,E是什么类型,ArrayList集合中就存什么类型,而且其成员方法都带有<E>

        public boolean add(E e)

        Iterator<E> it = arr.iterator();

    例子见Iterator

    7.3 带泛型的方法

    看一段ArrayList类的add方法:

    定义ArrayList方法使用的泛型类型是什么, 泛型方法的E就是什么类型

    7.4 带泛型的接口

    List接口就是一个带泛型的接口

    api手册中倒找List接口

    可见,我们在项目中定义类的时候,可以先实现接口,不理会泛型,这样,调用者在new对象的时候再来指定类型

    7.5 使用泛型的好处总结

        解决了强转时的安全问题

        将错误从运行时提前到了编译时

        增加了开发和调用者的灵活性

        泛型的出现,带来了增强型for循环foreach的出现

    7.6 泛型通配符 ?

    例:定义一个函数,可以同时迭代不同泛型类型的集合

    可见,由于ArrayList是List派系的,HashSet是Set派系的,因此参数必须使用List和Set派系的父类接口Collection。总之需要向上找相同的父类。

    由于?通配符不知道什么类型,因此不能做强转

    7.7 泛型的限定

    相关文章

      网友评论

          本文标题:Java之集合框架和泛型

          本文链接:https://www.haomeiwen.com/subject/fxzyvftx.html