Java:集合框架

1.Collection接口

        collection接口是Java最基本的集合接口,它定义了一组允许重复的对象。它虽然不能直接创建实例,但是它派生了两个字接口List和Set,可以使用子接口的实现类创建实例。Collection 接口是抽取List接口和Set接口共同的存储特点和操作方法进行的重构设计。Collection接口提供了操作集合以及集合中元素的方法。Collection接口的常用方法如下表:

方法声明功能描述
boolean add(Object obj)向集合中添加一个元素
boolean addAll(Collection c)将指定集合中所有元素添加到当前集合中
void clear()清空集合中的所有元素
boolean contains(Object obj)判断集合中是否包括某个元素
boolean containsAll(Collection c)判断集合中是否包含指定集合中的所有元素
Iterator iterator()返回在Collection的元素上进行迭代的迭代器
boolean remove(Object o)删除集合中的指定元素
boolean removeAll(Object o)删除指定集合中所有元素
boolean retainAll(Collection c)仅保留当前Collection中那些也包含在指定Collection的元素
Object[] toArray()返回包含Collection中所有元素的数组
boolean isEmpty()如果集合为空,则返回true
int size()返回集合中元素个数

        图示方法是集合的共性方法,这些方法即可以操作List集合,又可以操作Set集合。

2.List接口

        List接口是单列集合的一个重要分支,一般将实现了List接口的对象称为List集合。List集合中的元素是有序且可重复的,相当于数学里面的数列,有序、可重复。List集合的List接口记录元素的先后添加顺序,使用此接口能够精确地控制每个元素插入的位置,用户也可以通过索引来访问集合中的指定元素。

        List接口作为Collection接口的子接口,不但继承了Collection的所有方法,而且增加了一些操作List集合的特有方法,如下表:

方法声明功能描述

void add(int index,Object element)

在index位置插入element元素
Object get(int index)得到index出的元素
Object set(int index ,Object element)用element替换index位置的元素
Object remove(int index)移除index位置的元素,并返回元素
int indexOf(Object o)返回集合中第一次出现o的索引,若集合中不包含该元素,则返回-1
int lastIndex(Object o)返回集合中最后一次出现o的索引,若集合中不包含该元素,返回-1

上表列出了List接口的常用方法,所有List实现类都可以通过调用这些方法对集合元素进行操作。

创建一个List对象的语法格式如下:

List 变量 =new 实现类();

3.1ArrayList类

        ArrayList类是动态数组,用MSDN中的说法,就是数组的复杂版本,它提供了动态增加和减少元素的方法,继承AbstractList类,实现了List接口,提供了相关的添加、删除、修改、遍历等功能,具有灵活地设置数组大小的优点ArrayList实现了长度可变的数组,在内存中分配连续的空间,允许不同类型的元素共存。ArrayList类能够根据索引位置快速地访问集合中的元素,因此,ArrayList集合遍历元素随机访问元素的效率比较高。

        ArrayList类中大部分方法都是从List接口继承过来的。

        ArrayList的底层使用数组来保存元素的,用自动扩容机制实现动态增加容量。因为它的底层是用数组实现的,所以插入和删除操作的效率不佳,不建议用ArrayList做大量的增删操作。但是由于它有索引,所以查询效率很高,适合用来做大量查询操作

3.2LinkedList类

     为克服ArrayList集合查询速度快,增删速度慢的问题,可以使用LinkedList实现类。

        LinkedList底层的数据结构是基于双向链表的,它的底层实际上是由若干个相连的Node节点组成的,每个Node节点都包含该节点的数据、前一个结点、后一个节点。LinkedList集合添加元素如图①,LinkedList集合添加元素如图②。

        和ArrayList使用数据结构不同的是,链表结构的优势在于大量数据的添加和删除,但并不擅长依赖索引 的查询,因此,LinkedList在执行像插入或者删除这样的操作时,效率是很高的,但是随机访问方面就弱了很多。

        如图示,LinkedList类的方法大多是围绕头尾进行操作的,所以他对首尾元素的操作效率高。 

4.集合的迭代操作

4.1Iterator接口 

         Java提供了一个专门用于遍历集合的接口--Iterator,它是用来迭代访问Colllection中元素的,因此也称为迭代器。通过Collection接口中的iterator()方法可以得到集合的迭代器对象,只要拿到这个对象,使用迭代器就可以遍历集合。

TestIterator.java
public class TestIterator{
    public static void main(String[] args){
        List catList=new ArrayList();    //创建流浪猫集合
        Cat catl=new Cat("小哺",'母',"橘猫","收留");
        Cat cat2=new Cat("小米",'公',"三花","收留");
        Cat cat3=new Cat("小",'母”,"奶牛,"领养");
        catList.add(cat1);
        catList.add(cat2);
        catList.add(cat3);
        Iterator iterator=catList.iterator();    //获取Iterator 对象                                 
        while(iterator.hasNext()){ //判断集合中是否存在下一个元素
            Cat ele=(Cat)iterator.next(); //输出集合中的元素
            System.out.println(ele);
        }
    }
}

调用ArrayList的iterator()方法获得迭代器的对象,然后使用hasNext()方法判断集合中是否存在下一个元素,若存在,则通过next()方法取出。这里要注意,通过next()方法获取去元素时,必须调用hasNext()方法检测是否存在下一个元素,若元素不存在,会抛出NoSuchElementException异常。Iterator仅用于遍历集合,如果需要创建对象,则必须有一个被迭代的集合。

        在Iterator使用next()方法之前,迭代器游标在第一个元素之前,不知想任何元素,在第一次调用next()方法后,迭代器游标会后移一位,指向第一个元素并返回,依此类推,当hasNext()方法返回false时,则说明达到集合末尾,停止遍历。

4.2foreach遍历集合

        Java还提供了一种很简洁的遍历方法,即使用foreach循环遍历集合,它既能遍历普通数组,也能遍历集合。其语法格式如下:

for(容器中元素类型 临时变量:容器变量){
    代码块
}

从上述语法格式可以看出,与普通的for循环不同的是,foreach循环不需要获取容器的长度,不需要用索引去访问容器中元素,但是它能自动遍历容器中所有元素。

5.Set接口

        Set接口是单列集合的一个重要分支,一般将实现了Set接口的对象称为Set集合。Set集合中元素是无序的、不可重复的。严格地说,是没有按照元素的插入顺序排列。

        Set集合判断两个元素是否相等用equals()方法,而不是使用“=”运算符。如果两个对象比较就,equals()返回true,则Set集合是不会接受这两个对象的。Set集合可以储存null,但是只能储存一个,即使添加多个也只能储存一个。

        Set接口也继承了Collection接口,但是它没有对Collectionjk的方法进行扩充。Set接口的主要实现类是HashSet和TreeSet。其中,HashSet根据对象的哈希值来确定元素在集合中的存储位置,能高效的查询,可以用来做少量数据的插入操作;TreeSet底层是 用二叉树来实现存储元素的,它可以对集合中的元素进行排序。 

5.1HashSet类   

        HashSet按照Hash算法来确对象在集合中的储存位置。因此,具有很好的存取和查找性能。Set集合和List集合存取元素的方式是一样的。 

 5.2TreeSet类                                                                                    

         TreeSet集合和HashSet集合都可以保证容器内元素的唯一性,但是它们底层实现方式不同,TreeSet底层是用自平衡的排序二叉树实现的,所以它既能保证元素的唯一性,又可以对元素进行排序。TreeSet类还提供一些特有的方法,如下表示:

      

        TreeSet有两种排序方法:自然排序和定制排序。默认情况下,TreeSet采用自然排序。

         1.自然排序

TreeSet类会调用集合元素的comparable(Object obj)方法来比较元素的大小,然后将集合内的元素按升序排序,这是自然排序。

        Java提供了Comparable接口,它里面定义了一个comparableTo(Object obj)实现Comparable接口必须实现该方法,在方法中实现对象大小比较。当该方法被调用时,如obj1.compare To(obj2),若该方法返回0,则说明obj1和obj2相等;若该方法返回一个正数,则说明obj1大于obj2;若该方法返回一个负数,则说明obj1小于obj2.

        如果把一个对象添加到TreeSet集合,则该对象必须实现Comparable接口,否则程序会抛出ClassCastException异常。

        另外,向TreeSet集合中添加的应该是同一个类的对象,否则运行结果也会报ClassCastException异常。

        2.定制排序

         TreeSet的自然排序根据集合元素大小,按升序排序,如果需要按特殊规则排序或者元素本身不具备比较性,比如按降序排列,这时候就需要用到定制排序。Comparator接口包含一个int compare(T  t1,T  t2)方法,该方法可以比较t1和t2大小,返回正整数,则说明t1大于t2;若返回0,则说明t1等于t2;若返回负整数,则说明t1小于t2.

        要实现TreeSet的定制排序,只需在创建TreeSet对象时,提供Comparator对象与该集合关联,并在Comparator中编写排序逻辑。

import java.util.*;
public class TestTreeSetSort{
    public static void main(string[] args){
    //创建TreeSet集合对象时,提供一个Comparator对象
        TreeSet tree=new TreeSet(new MyComparator ()); 
        tree.add(new Student(140));
        tree.add(new Student(15));
        tree.add(new Student(11));
        system.out.println(tree);
    }
 }
    Class Student{
     //定义Student类
        private Integer age;
        public Student (Integer age){
            this.age=age;
        }
        public Integer getAge(){
            return age;
        }
        public void setAge (Integer age){
            this.age=age;
        }
        public String toString(){
            return age+"";
        }
}
class MyComparator implements Comparator{ //实现Comparator接口
    //实现一个campare方法, 判断对象是否是特定类的一个实例
    public int compare (Object o1,0bject o2){
        if(o1 instanceof Student&o2 instanceof Student){
            Student s1=(Student)o1; //强制转换为Student类型
            Students2=(Student) o2;
            if(s1.getAge()>s2.getAge()){
                return -1;
            }elseif(s1.getAge()<s2.getAge()){
                return 1;
            }
        }
            return 0;
    }
}

6.Map接口

6.1Map简介 

        Map接口不继承Collection接口,它与Collection接口是并列存在的,用于存储键值对形式的元素,描述了由于不重复的键到值的映射。

        Map中key和value都可以是任何引用类型的的数据。Map中key用Set来存放,不允许重复,及同一个Map对象所对应的类,必须重写hashCode()方法和equals()方法。通常用String类作为Map的key,key和value之间存在一对一的关系,即通过指定的key总能遭到唯一的、确定的value。Map接口的方法如下图示:

 6.2HashMap类

        HashMap类是Map接口中使用频率最高的实现类,允许使用null键和null值,与HashSet集合一样,不保证映射的顺序。HashMap集合判断两个key相等的标准:两个key通过equals()方法返回true,hashCode值也相等。HashMap集合判断两个value相等的标准:两个value通过equals()方法返回true。由于HashMap集合中的键是用Set来储存的,所以不可以重复。 

当键重复时,后添加元素的值,覆盖了先添加的元素的值,简单来说就是键相同,值覆盖。

        遍历Map的方式有两种,第一种是先遍历所有的键,再根据键获得对应的值。第二种遍历方式是先获得集合所有的映射关系,然后再根据映射关系获取键和值

6.3LinkedHashMap类

        LinkedHashMap类是HashMap的子类,LinkedHashMap类可以维护Map的迭代顺序,迭代顺序与键值插入顺序一致。如果需要输出顺序与输入时顺序相同,那么就用LinkedHashMap集合。

6.4Properties类

        Map接口中有一个古老的、线程安全的实现类--Hashtable,与HashMap集合相同的是,他也不能保证其中键值对的顺序,他判断两个键、两个值相等的标准与HashMap集合一样,与HashMap集合不同的是,他不允许使用null作为键和值

        Hashtable类存取元素速度较慢,目前基本被HashMap类代替,但是他有一个子类Properties在实际开发中 很常用,该子类对象处理文件,由于属性文件里的键和值都是字符串类型的,所以Properties类的键和值都是字符串类型的。

 7.1为什么要使用泛型

        为了解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识,表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或者实例化时只要指定好需要的具体类型即可。

        Java泛型可以保证程序在编译时如果没有发出警告,运行时就不会报ClassCastException异常,同时,代码更加简洁、健壮。

7.2泛型的定义

        在定义泛型时,使用“<参数化类型>”的方式指定集合中方法操作的数据类型,具体示例如下。

ArrayList <参数化类型> list =new ArrayList<参数化类型>();

        在创建集合的时候,如果指定了泛型为String类型,该集合只能添加String类型的元素,编译文件时,不再出现类型安全警告,如果向集合中添加非String类型的元素,则会报编译时异常。

7.3通配符

        这里要引入一个通配符的概念,类型通配符用符号“ ?”表示,比如List<?>,它是List<String>、List<Object>等各种泛型的父类。

import java.util.*;
public class TestGeneric2{
    public static void main(String[] args){
        //声明泛型类型为“?”
        List<?> list=null;
         list=new ArrayList<String>();
         list=new ArrayList<Integer>(); //编译时报错
         //list.add(3);
         list.add(null); //添加元素null
         System.out.println(list);
         List<Integer> 11=new ArrayList<Integer>();
         List<String>l2=new ArrayList<String>();
         l1.add(1000);
         12.add("phone");
         read(ll);
         read(l2);
     }
     static void read(List<?> list){
         for(0bjecto:list){
             System.out.println(0);
         }
     }
 }

        先声明List的泛型类型为“ ?”,然后在创建对象实例时,泛型类型设为String或者Integer都不会报错,这体现了泛型的可扩展性,此时向集合中添加元素会报错,因为List的元素类型无法确定,唯一的例外是null,它是所有类型的成员。

        另外,在方法read()的参数声明中,List参数也应用了泛型类型“?”,所以使用此静态方法能接收多种类型。

7.4自定义泛型

        假设要实现一个简单的容器,用于保存某个值,这个容器应该定义两个方法--get()方法和set(),前者用于取值,后者用于存值,如法格式如下:

void    set(参数类型 参数){...}
返回值 参数类型 get(){...}

  • 8
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值