集合、泛型

来源:互联网 发布:如何建立图片数据库 编辑:程序博客网 时间:2024/06/06 14:26

集合
集合中存储的都是对象的引用(地址)
集合获取元素的方式:迭代器(iterator)
集合的理解:
java是一种面向对象语言,如果我们要针对多个对象进行操作,就必须对多个对象进行存储。
而对多个元素进行存储,前面我们学习过数组,数组的弊端,长度固定。这样,数组将不能
满足变化的要求。所以,java就提供了集合供我们使用。

集合的特点:
1、长度可以发生改变
2、只能存储对象
3、可以存储多种类型对象(一般存储的还是同一种)
集合和数组的区别
1、长度问题
数组固定
集合可变
2、存储元素问题
数组可以是基本类型,也可以是引用类型。
集合只能是引用类型。
3、是否同一类型
数组元素类型一致。
集合元素类型可以不一致。
4、集合体系的由来
集合是存储多个元素的容器,但是,由于数据结构不同,java就提供了多种集合类。
而这多种集合类有共性的功能,所以,通过不断的向上抽取,最终形成了集合体系结构。
集合框架:


Collection接口:Collection接口是所有单列集合的父接口
        |---list:元素是有序的,元素可以重复,因为该集合体系中有索引
            |---ArrayList:底层使用的是数组结构,查询快,增删慢,判断元素唯一的方法是:equals    线程不同步
                想建立自己特有的比较方式,只要在类中复写equals方法,建立子类特有的比较方式即可,使用contains方法,就会调用equals比较
            |---LinkedList:底层使用的是链表结构。增删快,查询慢
            |---Vector:底层使用的是数组结构,增删查都慢    线程同步
                
ArrayList和Vector的区别:
                        默认数组长度都为10,超出后,ArrayList每次增长50%,Vector每次增长100%
                        ArrayList和Vector都可以初始默认的长度
                LinkedList的特有方法:
                        addFirst():向集合的开始位置追加元素
                        addLast():向集合的尾部位置追加元素
                        getFirst():获取集合的开始元素(获取元素,不删除,长度不变)
                        getLast():获取集合的尾部元素
                        如果集合中没有元素,会出现:NoSuchElementException异常(没有元素异常)
                        removeFirst():删除集合开始位置的元素(获取元素,删除元素,长度变化)
                        removeLast():删除集合尾部位置的元素
                        如果集合中没有元素,会出现:NoSuchElementException异常
             JDK1.6版本以后出现了替代方法:
                        offerFirst()、offerLast()
                        peekFirst()、peekLast()如果集合中没有元素,返回 null
                        pollFirst()、pollLast()如果集合中没有元素,返回 null
        
        对List集合的遍历:
              1、for循环 for(int i =0;i<list.size();i++){ list.get(i) }
              2、Iterator进行遍历
              3、ListIterator列表迭代器
              4、增强for循环

 list    常用方法:
                   增:
                        add()
                        addAll()
                    删:
                        remove()
                        remove(位置):删除指定位置的元素
                   改:
                        set(位置,新值):将指定位置的值替换
                   查:
                        get(位置):获取指定位置上的元素
                        size():获取集合的大小
                        subList(起始位置,结束位置):获取包含头不包含尾的元素
                        indexOf():获取对象第一次出现的位置
                        lastIndexOf():获取元素最后一次出现的位置

                Iterator():迭代器
                        hasNext()判断是否还有下一个元素
                        next()获取下一个元素
                        remove()删除元素
List集合特有的迭代器:    ListIterator 它是 Iterator的子类接口    
                ListIterator():列表迭代器
                       add()插入
                       hasNext()正向判断是否还有下一个元素
                        hasPrevious()逆向遍历
                       next()返回下一个元素
                        previous()返回前一个元素
                        remove()删除元素
                        set()替换(修改)
ArrayList代码演示
package Demo;import java.util.*;class ListDemo {//输出方法public static void sop(Object obj){System.out.println(obj);}public static void method(){ArrayList al = new ArrayList();//添加元素al.add("java01");al.add("java02");al.add("java03");sop("原集合是:"+al);//在指定位置添加元素。al.add(1,"java09");//删除指定位置的元素。//al.remove(2);//修改元素。//al.set(2,"java007");//通过角标获取元素。sop("get(1):"+al.get(1));sop(al);//获取所有元素。for(int x=0; x<al.size(); x++){System.out.println("al("+x+")="+al.get(x));}Iterator it = al.iterator();//Iterator迭代器获取元素while(it.hasNext()){sop("next:"+it.next());}//通过indexOf获取对象的位置。sop("index="+al.indexOf("java02"));List sub = al.subList(1,3);sop("sub="+sub);}public static void main(String[] args) {//演示列表迭代器。ArrayList al = new ArrayList();//添加元素al.add("java01");al.add("java02");al.add("java03");sop(al);ListIterator li = al.listIterator();//sop("hasPrevious():"+li.hasPrevious());while(li.hasNext()){Object obj = li.next();if(obj.equals("java02"))//li.add("java009");li.set("java006");}//逆序遍历集合内容while(li.hasPrevious()){sop("pre::"+li.previous());}sop(al);}}


        |--- set:元素是无序的(存入和取出的元素顺序不一致),元素不可以重复
            ---HashSet:内部数据结构是哈希表,判断元素唯一:HashCode和equals            (默认长度:16)
                                (先判断哈希值是否相同,相同在比较两个元素的equals,如果相同,视为同一元素)
                         注意:对于判断元素是否存在,以及删除等操作,依赖的方法是:HashCode和equals方法
                                  (先判断哈希值是否相同,不同,直接删除;相同在比较元素的equals,相同删除)
           
            --- TreeSet:内部数据结构是二叉树,按照自然顺序存放。                                        (默认长度:空)
                                判断元素唯一的依据是:实现Comparable接口覆盖CompareTo方法,return返回0
                                (进行排序时,当主要条件相同,就按照次要条件进行排序,如果仍然相同,元素相同,不存)
                         可以对Set集合中的元素进行排序(内部是有序的,按照自然顺序存放
                        TreeSet排序第一种方式:让元素自身具备比较性
                                实现Comparable接口,覆盖compareTo方法自然顺序排序
                         TreeSet排序第二种方式:让容器具备比较性
                                当元素自身不具备比较性时,或者具备的比较性不是想要的,
                                让集合自身具备比较性:定义一个比较器,将比较器对象作为参数传递给TreeSet集合
                                比较器:实现Comparator接口,覆盖compare方法
                                        class MyCompare implements Comparator
                                        {
                                                    public int compare(Object o1,Object o2){

                                                    }
                                        }
                                        让容器具备比较性:TreeSet ts=new TreeSet(new MyCompare)
                            当两种元素都存在时:以比较器为主
       Set集合的迭代元素的方式:
                            1、Iterator迭代器
                            2、增强for循环
            

哈希表的原理: 

1,   对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值称为哈希值。 

2,   哈希值就是这个元素的位置。 

3,   如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。 

4,   存储哈希值的结构,我们称为哈希表。 

5,既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。 这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。

  对于ArrayList集合,判断元素是否存在,或者删元素底层依据都是equals方法。 

对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。


Set集合练习
向HashSet集合中学生对象,并且姓名和年龄相同的视为同一个人
class Demo{public static void main(String [] args){//创建HashSet对象HashSet<Student1> hs=new HashSet<Student1>();//向集合中添加学生对象hs.add(new Student1("lisi",10));hs.add(new Student1("wangwu",10));hs.add(new Student1("lisi",10));System.out.println(hs);}}//创建学生对象class Student1{private String name;private int age;Student1(){}Student1(String name,int age){this.name=name;this.age=age;}public void setName(String name){this.name=name;}public void setAge(int age){this.age=age;}public String getName(){return name;}public  int getAge(){return age;}//复写toString方法public String toString(){return name+"="+age;}//复写HashCode和equals方法,保证元素唯一public int hashCode(){return this.name.hashCode()+age*3;}public boolean equals(Object obj){Student1 stu=(Student1)obj;return this.name.equals(stu.name) && this.age==stu.age;}}

Map集合(接口):
Map集合是双列集合的父接口
     
       Map 集合的特点:集合中存储键值对,键和值一一对应,要保证键的唯一性(键值不能重复)
       Map集合中的方法:
               1、添加:
                        put(key,value):添加元素
                                                        
当存储的键值相同时,新的值会替换旧值,并将旧值返回
                                                         如果键值没有重复,则返回null
                        putAll( Map< K ,   V  >):添加一个集合元素
               2、删除:
                        clear():清除
                        remove(Key):根据键,删除键值对    并将删除的值返回
               3、判断:
                        containsKey(key):是否包含某个键
                        containsValue(Value):   是否包含某个值
                        isEmpty():判断是否为空
               4、获取:
                        get(key):给定  ,返回对应的 
                        size():获得Map集合中的键值对数
                        values():返回Map集合中所有的值,返回值为:Collection集合
                            Collection<>    c = map.values()
                    重点:Map集合的遍历
                            entrySet():将Map集合的键值存入到Set集合
                            KeySet():将Map集合的键值存入到Set集合
        
       Map:Set集合底层就是使用了Map集合
            |--- Hashtable    底层是哈希表数据结构,线程同步,不可以存储null键和null值(默认长度:11)
            |--- HashMap     底层是哈希表数据结构,线程不同步,可以存储null键和null值(默认长度:16)
                                作为键的自定义对象,必须实现HashCode方法和equals方法

            |--- TreeMap底层是二叉树结构,进行自然顺序排序默认长度:空)
可以对Map集合中的键进行指定顺序的排序
1、实现 comparable 接口,覆盖 compareTo 方法
2、让集合自身具备比较性:定义一个比较器,将比较器对象作为参数传递给TreeSet集合
比较器:实现Comparator接口,覆盖compare方法
                                           
class MyCompare implements Comparator{public int compare(Object o1,Object o2){}}//让容器具备比较性:TreeMap ts=new TreeMap(new MyCompare)

        Map集合的两种取出方式:
               1、keySet:将map集合中的所有键存入到Set集合中,因为Set具备迭代器
                                    可以用迭代方式去除所有的键,在根据get方法获取每一个键对应的值
Map<String,String> mp = new HashMap<String,String>mp.put("","");Set<String> keySet=mp.KeySet();   //将Map集合的所有键存入到Set集合中Iterator < String >  it = keySet.Iterator();    //利用Set集合的的Iterator迭代器获取到所有的键while(it.hasNext()){String  key = it.next();   //得到所有的键String value = mp.get(key);//根据键得到Map集合中的所有值}

              

               2、entrySet:将Map集合中的映射关系,存入到Set集合中
Map< String,String > mp = new HashMap< String,String >();mp.put("","");Set < Map . Entry< String,String > > entrySet = mp.entrySet(); //将map集合利用entry存入到Set集合中    类型为:Map . Entry类型Iterator < Map . Entry< String,String > > it=entrySet.iterator();//利用Set的迭代器,将Map集合的键值映射关系进行迭代while(it.hasNext()){Map.Entry< String,String > map=it.next();String key = map.getKey();//利用getKey方法取出键String value = map.getValue();//利用getValue方法取出值}



            Map . Entry :    其实Entry也是一个接口,它是Map借口的一个内部接口
interface Map{   public static interface Entry{   public abstract Object getKey();   public abstract Object getValue();  }}

TreeMap存入自定义学生对象,实例:
将学生的姓名和年龄存入到Map集合中,并按照学生的年龄排序,如果年龄相等,按照姓名排序;姓名和年龄都相等视为同一个学生
public class Student {private String name;private int age;//空参构造函数public Student() {}//带参构造函数public Student(String name, int age) {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;}}<pre name="code" class="java">//将学生的姓名和年龄存入到Map集合中,并按照学生的年龄排序,如果年龄相等,按照姓名排序;姓名和年龄都相等视为同一个学生
public class TreeMapDemo{<span style="white-space:pre"></span>public static void main(String[] args) {<span style="white-space:pre"></span>// 创建集合对象,传入一个匿名对象比较器<span style="white-space:pre"></span>TreeMap<Student, String> tm = new TreeMap<Student, String>(<span style="white-space:pre"></span>new Comparator<Student>() {<span style="white-space:pre"></span>public int compare(Student s1, Student s2) {<span style="white-space:pre"></span>int num = s2.getAge() - s1.getAge();<span style="white-space:pre"></span>//1、按照年龄排序<span style="white-space:pre"></span>int num2 = (num == 0) ? s1.getName().compareTo(s2.getName()) : num;<span style="white-space:pre"></span><span style="font-family: 微软雅黑;">//2、按照姓名排序</span><span style="white-space:pre"></span>return num2;<span style="white-space:pre"></span>}});<span style="white-space:pre"></span>// 创建元素对象<span style="white-space:pre"></span>Student s1 = new Student("李世民", 30);<span style="white-space:pre"></span>Student s2 = new Student("朱元璋", 40);<span style="white-space:pre"></span>Student s3 = new Student("武则天", 50);<span style="white-space:pre"></span>Student s4 = new Student("武则天", 50);<span style="white-space:pre"></span>Student s5 = new Student("武则天", 30);<span style="white-space:pre"></span>// 添加元素<span style="white-space:pre"></span>tm.put(s1, "it001");<span style="white-space:pre"></span>tm.put(s2, "it002");<span style="white-space:pre"></span>tm.put(s3, "it003");<span style="white-space:pre"></span>tm.put(s4, "it004");<span style="white-space:pre"></span>tm.put(s5, "it005");<span style="white-space:pre"></span>// 遍历<span style="white-space:pre"></span>Set<Student> set = tm.keySet();<span style="white-space:pre"></span>for (Student key : set) {<span style="white-space:pre"></span>String value = tm.get(key);<span style="white-space:pre"></span>System.out.println(key.getName() + "***" + key.getAge() + "***"+ value);<span style="white-space:pre"></span>}<span style="white-space:pre"></span>}}

工具类:
            Collections:集合工具类,专用来对集合进行操作的
                    sort(List集合):对List集合进行排序
                    sort(List集合,new 比较器)
                                如果想按照自定的顺序进行排序,定义一个类实现Comparator接口,复写compare方法
                    max:获取集合中的最大值
                    binarySearch:对集合进行二分查找(只要是二分查找,就必须是有序的)
                    fill(集合,“字符串”):将集合中的元素全都替换为指定的字符串
                    replaceAll(集合,旧字符串,新字符串):将集合中的元素替换为指定元素
                    reverse(集合):将集合进行反转
                    reverseOrder(集合):返回一个比较器,将集合的(比较器的)顺序进行逆转
                            TreeSet ts = new TreeSet( Collections.reverseOrder( ) )(将集合进行逆序)
                  TreeSet ts = new TreeSet( Collections.reverseOrder( 自定义的比较器)) (将已有比较器进行逆转)
Arrays:数组工具类,专门用来对数组进行操作的工具类
                asList:讲数组转换为list集合
                binarySearch:数组二分查找
                equals:判断两个数组是否相等
                sort:对数组进行自然顺序排序
                toString:将数组转换为字符串
        Collection和Collections的区别:
                Collection是java.util下的接口,单例集合的顶层接口,继承与它的接口主要有:                        List和set接口提供了关于集合的一些操作,如:添加、删除、遍历、判断一个元素是否是集合中的成员等                Collections是java.util下的一个更具类,它提供一系列的静态方法,实现了对集合的查找、排序sort、替换replaceAll等操作
        
        集合那么多什么时候该用谁? 
                是否键值对?是:Map,是否对键排序?是:TreeMap否:HashMap不懂的情况就用HashMap 
                                    否:Collection,是否唯一?是:Set,是否对元素进行排序?是:TreeSet否:HashSet不懂的情况下,使用HashSet 
                                                                                否:List,是否要安全?是:Vector(真正开发中也不用)否:ArrayList,LinkedList
        注意:
                查询多:ArrayList增删多:LinkedList不懂的情况下,使用ArrayList
泛型:
JDK1.5以后出现的新特性,用于解决安全问题,是一个安全机制
        泛型的好处:
               1、将运行时期出现的问题,ClassCaseException(类型转换异常),转移到了编译时期,方便与程序员解决问题,让运行问题减少、比较安全!
                2、避免了前置转换的麻烦

        泛型的格式:通过<>来定义操作的引用数据类型

        在使用java提供的对象时,什么时候写泛型?
                通常在集合框架中很常见,只要见到 < > 就要定义泛型
                < > 就是用来接收类型的

         当使用集合时,将集合中要存储的数据类型作为参数传递到 < > 中即可

泛型类:
            当类中要操作的引用数据类型不确定的时候,JDK1.4版本以前,用Object类完成扩展
            JDK1.5版本以后,用    泛型    完成扩展
            class Demo < T > {   }
泛型类演示:
class Utils<QQ><span style="white-space:pre"></span>//泛型定义在类上{private QQ q;public void setObject(QQ q){this.q = q;}public QQ getObject(){return q;        }}


泛型方法:
            为了让不同方法可以操作不同类型,而且类型还不确定,就可以将泛型定义在方法上
            public < T > void method ( T t ) {   } 
泛型方法示例
class Demo<T>{public  void show(T t){System.out.println("show:"+t);}public <Q> void print(Q q)<span style="white-space:pre"></span>//泛型定义在方法上{System.out.println("print:"+q);}public  static <W> void method(W w)<span style="white-space:pre"></span>//泛型定义在静态方法上{System.out.println("method:"+w);}}



静态方法泛型:(如果类中的静态方法需要泛型,那么泛型一定定义在方法上)
            静态方法不可以访问类上定义的泛型
            如果静态操作的引用数据类型不确定,那么可以将泛型定义在方法上
            public static < T > void method ( T t ) {  }

泛型接口:         
interface Inter < T >{<span style="white-space:pre"></span>//泛型接口 void show ( T t )}


代码示例:
interface Inter<T><span style="white-space:pre"></span>//泛型接口{void show(T t);}class InterImpl<T> implements Inter<T><span style="white-space:pre"></span>//实现了接口的泛型类{public void show(T t){System.out.println("show :"+t);}}



  用泛型有好出,可以限定传入的类型,但弊端是:泛型不明确,不能使用类型特有的方法

泛型的高级应用:泛型的限定,适用于泛型扩展(只能够使用父类中的方法)
            ?    :占位符
            < ?  extends  E >    可以接受  E  类型或者 E 类型的子类型    上限

            <  ?  super  E >        可以接受 E 类型或者 E 类型的父类型    下限
             代码示例:
public static void printColl(Collection<? extends Person> al)<span style="white-space:pre"></span>//定义一个方法可以接受Person类和Person的子类{   Iterator<? extends Person> it = al.iterator();   while(it.hasNext()){   System.out.println(it.next().getName());  }}




0 0
原创粉丝点击