黑马程序员_java集合框架上

------ android培训java培训java博客、java学习型技术博客、期待与您交流! -------

一、集合框架

  1.0、集合类:

为什么出现集合类?面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。

1.1、数组和集合类同是容器,有何不同?

数组虽然可以存储对象,但是长度是固定的;集合长度是可变的,数组可以存储基本数据类型,集合只能存储对象。

     1.2集合类的特点:

         集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。 

Collection

 |--List:元素是有序的,元素可以重复。因为该集合体系有索引。

      |--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快,但删除稍慢。线程不同步。

      |--LinkedList:底层使用的是链表数据结构。特点:增删速度很快,查询稍慢。

      |--Vector:底层是数组数据结构。线程同步(线程安全)。被ArrayList替代

 |--Set :元素是无序,元素不可以重复。

      |--HashSet:底层数据结构是哈希表。

      |--TreeSet

List:

      特有方法,凡是可以操作角标的方法都是该体系特有的方法。

   add(int index,Object element);//在指定位置添加元素

   addAll(int index,Collection<? extends E> co);//将指定collection中的所有元素都插入到列表中的指定位置

   E remove(int index);//删除指定位置的元素,将所有的后续元素向左移动(将其索引减1),返回从列表中移除的元素。

   boolean remove(Object obj);//移除列表中出现的首个指定元素,如果列表不包含元素,则不更改列表。移除具体满足下面条件的最低索引i的元素:

obj==null?get(i)==null:obj.equals(get(i))r如果存在这样的元素。

   set(int index,Object element)//修改指定位置元素,index-要替换的元素的索引。element-要在指定位置存储的元素。

抛出:

UnsupportedOperationException-如果列表不支持 set 方法。

ClassCastException-如果指定元素的类不允许它添加到此列表。

NullPointerException-如果指定的元素为 null,并且此列表不支持 null 元素。

IllegalArgumentException-如果指定元素的某个方面不允许它添加到此列表。

IndexOutOfBoundsException-如果索引超出范围 (index < 0 || index >= size())

   E get(int index);//返回列表中指定位置元素,index-要返回的元素的索引

   抛出:

IndexOutOfBoundsException-如果索引超出范围 (index < 0 || index >= size())

   List<E> subList(int from,int to);//包含头(from)不包含尾(to)取元素(如果fromto相等,则返回的列表为空)

   list.subList(from,to):此方法返回一个新的list集合。

   List.subList(from,to).clear():此语句从列表中移除了元素的范围,原集合返回移除后剩下的所有元素

   ListIterator<E>接口;此接口是Iterator的子接口,系列表迭代器,允许程序员按照任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。ListIterator没有当前元素;它的光标位置始终位于调用previous()所返回的元素和调用next()返回的元素之间。在长度为n的列表中,有n+1个有效的索引值,从0n(包含0

注意:remove()set(Object)方法不是根据光标位置定义的;它们是根据对调用next()previous()所返回的最后一个元素的操作定义的。

boolean hasPrevious(),如果反向遍历列表,列表迭代器有多个元素,则返回true

E previous()返回列表中的前一个元素。可以重复调用此方法来迭代列表,或混合调用next来前后移动(注意交替调用nextprevious将重复返回相同的元素)。

抛出:

NoSuchElementException-如果没有可迭代的上一个元素。

  int indexOf(Object obj);//获取对象第一次出现的位置,如果对象不存在则返回-1

List集合特有的迭代器。ListIteratorIterator的子接口,在用Iterator迭代时

不可以通过集合对象的方法操作集合中的元素,因为会发生ConcurrentModificationException异常。 

所以在迭代时,只能用迭代器的方法操作元素,可是Iterator方法是有限的。

只能对元素进行判断,取出,删除的操作,

如果想要其它的操作,如修改添加。就需要使用其子接口,ListIterator

该接口只能通过List集合的listIterator接口的方法获取。

一、

publicstaticvoiditerator(){

        ArrayList al=new ArrayList();

        al.add("java1");

        al.add("java2");

        al.add("java3");

        al.add("java4");

        Iterator it=al.iterator();

        while(it.hasNext()){

            Object obj=it.next();

            if(obj.equals("java2"))

                //al.remove(2);//集合对象操作会有异常

                               //it没有添加方法

                it.remove();//把这个元素引用从集合中移除,但元素还在内存中

            sop(obj);//元素还能被Object使用,所以全被打印了   

        }sop(al);//打印方法,打印出移除后的集合

    }

二、

   privatestaticvoid listIterator() {

        ArrayList al=new ArrayList();

        al.add("java1");

        al.add("java2");

        al.add("java3");

        ListIterator li=al.listIterator();

        while(li.hasNext()){

            Object obj=li.next();

            if(obj.equals("java2"))

            //li.add("java9");//java2的后面添加java9

            li.set("hello");//java2修改成hello

            sop(obj);//此处输出的永远是原集合中元素

        }

        sop(al);//修改后的集合中元素

    }

三、

    privatestaticvoid listIterator() {

        ArrayList al=new ArrayList();

        al.add("java1");

        al.add("java2");

        al.add("java3");

        ListIterator li=al.listIterator();

        System.out.print(li.hasPrevious());//指针没有前一个元素返回false

        while(li.hasNext()){//有下一个元素返回true,指针下移

            Object obj=li.next();

            System.out.print(obj);

        }

        sop(li.hasPrevious());//指针有前一个元素返回true

        while(li.hasPrevious()){//逆向判断,有前一个元素就为true

            System.out.print(li.previous());//逆序打印,previous()控制指针的跳跃个数,如果和要一个一个的打印,此处只能调用一次。

        }

    }

Vector:中的枚举

   Enumeration<E> elements():返回此向量的组件枚举。返回的Enumeration对象将生成此向量中的所有项。生成的第一项为0处的项,然后是索引1处的项,依次类推。

枚举是Vector特有的取出方式。枚举和迭代器很像,其实一样,因为枚举的名称以及方法名称都过长,

所以被迭代器取代了。

publicstaticvoid vectorDemo(){

        Vector v=new Vector();

        v.add("java1");

        v.add("java2");

        v.add("java3");

        Enumeration  e=v.elements();//枚举Vector特有方法

        while(e.hasMoreElements()){

            sop(e.nextElement());

        }

    }

LinkedList:特有方法

       addFirst(E o);//将给定元素o插入此列表的开头,添加后,取出打印结果是倒序

       addLast(E o); //将给定元素追加到此列表的结尾

 获取元素,但不删除元素,如果集合中没有元素,会出现NoSuchElementException

 getFirst();//返回此列表的第一个元素-java1

 getLast();//返回此列表的最后一个元素-java2

获取元素,但是元素被删除,如果集合中没有元素,会出现NoSuchElementException

 removeFirst();//移除并返回此列表的第一个元素。

 removeLast();//移除并返回此列表的最后一个元素。

JDK1.6出现了替代方法。

boolean offerFirst(E e);//将指定元素此双端列队的开头。

boolean offerLast(E e);//将指定元素插入此双端列队的末尾

获取元素,但不删除元素,如果集合中没有元素,会返回null

peekFirst();返回此双端列队的头部,如果此双端列队为空,则返回null

peekLast();

获取元素,但是元素被删除,如果集合中没有元素,会返回null

pollFirst();

pollLast();

例:

   publicstaticvoid linkedList(){

        LinkedList li=new LinkedList();

        li.addFirst("java1");

        li.addFirst("java2");

        li.addFirst("java3");

        while(!li.isEmpty()){

            sop(li.removeFirst());

        }

    }

使用LinkedList模拟一个堆栈或队列数据结构。

堆栈:先进后出,如图一个杯子;

队列:先进先出,如图一个水管;First in First outFIFO

 

import java.util.LinkedList;

class DuiLie{

    private LinkedListlink;

    DuiLie(){

        link=new LinkedList();

    }

    publicvoid myAdd(Object obj){

        link.addFirst(obj);

    }

    public Object myGet(){

        returnlink.removeLast();

    }

    publicboolean isNull(){

        returnlink.isEmpty();

    }

}

publicclass LinkedListTest {

    publicstaticvoid main(String[] args) {

        DuiLie dl=new DuiLie();

        dl.myAdd("java01");

        dl.myAdd("java02");

        dl.myAdd("java03");

        while(!dl.isNull()){

            System.out.println(dl.myGet());

        }

    }

}

|--Set :元素是无序,元素不可以重复。

      |--HashSet:底层数据结构是哈希表。线程不同步

 

          HashSet是如何保证元素唯一性的呢?

          是通过元素的两个方法,hashCodeequals来完成。

          如果元素的HashCode值相同,才会判断equals是否为true

          如果元素的hashCode值不同,才会调用equals       

注意:对于判断元素是否存在(contains),以及删除(remove)等操作,依赖的方法是元素的

       hashCodeequals方法。

       ArrayList依赖的只有equals方法。 

哈希表特点:我们想删除元素或想判断元素时,都必须的先判断哈希值。

例:HashSet集合中存入自定义对象

姓名和年龄相同为同一个人,重复元素。 

import java.util.HashSet;

import java.util.Iterator;

class People{

    private Stringname;

    privateintage;

    People(String name,int age){

         this.name=name;

         this.age=age;

    }

    publicint hashCode(){//两个相同的对象,比较哈希值是否相等,若相等再比较内容

     returnname.hashCode()+age*27;//此处乘以27解决有可能导致两个不同对象的哈希值相同,还的再去判断

                                             //equals,导致程序效率降低问题;

    }

    publicboolean equals(Object obj){//内容也相等则,不能存进去

         if(!(obj instanceof People))

             returnfalse;

         People p=(People)obj;

         System.out.println("hashCode值判断通过(相同)进入equals判断是否为true,为true即为相同元

                                           素不能插入HashSet集合");

         returnthis.name.equals(p.name)&&this.age==p.age;//姓名年龄都相等返回true

    }

    public String getName(){

         returnname;

    }

    publicint getAge(){

         returnage;

    }

}

publicclass HashSet{

    publicstaticvoid main(String[] args) {

    HashSet hs=new HashSet();

    hs.add(new People("a1",11));

    hs.add(new People("a2",12));

    hs.add(new People("a3",13));

    hs.add(new People("a2",12));

    Iterator it=hs.iterator();

    while(it.hasNext()){

         People p=(People)it.next();

         System.out.println(p.getName()+".."+p.getAge());

    }

  }

}

                   Day_15

|--Set :元素是无序,元素不可以重复。

      |--HashSet:底层数据结构是哈希表。线程不同步

      |--TreeSet:可以对Set集合中的元素进行排序。

                   底层数据结构是二叉树。

                   保证元素唯一性的依据:

                   compareTo方法return 0.

int compareTo(T o)

比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。 

Set详解:存入set的每个元素必须是唯一的,这也是与List不同的,因为Set不保存重复元素。加入SetObject必须定义equals()方法以确保对象的唯一性。SetCollection有完全一样的接口。Set接口不保证维护元素的次序。

HashSetHashSet能快速定位一个元素,存入HashSet的对象必须定义hashCode().

TreeSet:保持次序的Set,底层为二叉树结构。使用它可以从Set中提取有序的序列。

LinkedHashSet:具有HashSet的查询速度,且内部使用列表结构维护元素的顺序(插入的次序)。于是在使用迭代器遍历Set时,结果会按照元素的插入次序显示。

需要注意的是,生成自己的类时,Set需要维护元素的存储顺序,因此要实现Comparable接口定义compareTo方法。

     TreeSet排序的第一种方式:让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也称为元素的自然顺序,或者叫默认顺序。 

     TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。

强制让对象具备比较性:

import java.util.Iterator;

import java.util.TreeSet;

publicclass TreeSetDemo {

    publicstaticvoid main(String[] args) {

        TreeSet ts=new TreeSet();

        ts.add(new Student("a2",22));

        ts.add(new Student("a3",24));

        ts.add(new Student("a4",19));

        ts.add(new Student("a1",22));

        Iterator it=ts.iterator();

        while(it.hasNext()){

            Student s=(Student)it.next();

            System.out.println(s.getName()+"::"+s.getAge());

        }

    }

}

class Studentimplements Comparable{//强制让学生具备比较性

    private Stringname;

    privateintage;

    Student(String name,int age){

        this.name=name;

        this.age=age;

    }

    publicint compareTo(Object o) {

        if(!(oinstanceof Student))

            thrownew RuntimeException("不是学生对象");

        Student stu=(Student)o;

        if(this.age>stu.age)//当前元素>传入的元素

            return 1;

        if(this.age==stu.age){//主要条件

            returnthis.name.compareTo(stu.name);//次要条件

        }

        return -1;

    }

    public String getName(){

        returnname;

    }

    publicint getAge(){

        returnage;

    }

}

     TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。如果元素自身具备比较性,则以比较器为主

比较器:

class MyCompareimplementsComparator{

    publicint compare(Object o1,Object o2){

                if(o1 instanceof PeopleDemo || o2 instanceofPeopleDemo)

                throw new RuntimeException(不是同一种对象);

        PeopleDemo s1=(PeopleDemo)o1;

        PeopleDemo s2=(PeopleDemo)o2;

        int num= s1.getName().compareTo(s2.getName());//对象比较用compareTo

        if(num==0){

        //简化方式,对象封装,调用compareTo()

        returnnew Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));

            /*if(s1.getAge()>s2.getAge())

                return 1;

            if(s1.getAge()==s2.getAge())

                return 0;

            return -1;*/

        }

        return num;

    }

}

修改集合,为其添加比较器:

TreeSet ts=new TreeSet(new MyCompare());

--------------------------------

TreeSet练习:按照字符串长度进行排序。

class MyStrCompareimplementsComparator{

    publicint compare(Object o1,Object o2){

        String s1=(String)o1;

        String s2=(String)o2;

    int num=new Integer(s1.length()).compareTo(new Integer(s2.length()));

        if(num==0)//长度相等后

            return s1.compareTo(s2);//比较内容是否相同

        return num;

    }

}

总结:比较器如果作用于二叉树(TreeSet)排序结构,则直接在集合类参数中传入自定义比较器对象即可;

      如果作用在底层数组结构(ArrayList)或列表结构(LinkedList)的集合类中时用法:

      第一步:先对集合进行排序,a1代表集合引用

      Collections.sort(al,new MyComparator());

      第二步:根据迭代,最后输出结果

      自定义比较器不能作用在HashSet(底层哈希表结构)中,因为内存中不能存在相同对象,哈希值唯一。

 二、泛型JDK1.5版本以后出现的新特性。用于解决安全问题,是一个类型安全机制。

   好处:

1.将运行时期出现的问题ClassCastException,转移到了编译时期。方便程序员解决问题,让运行事情问题减少,安全。

2.避免了强制转换麻烦。

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

      在使用java提供的对象时,什么时候写泛型呢?

      通常在集合框架中很常见,只要见到<>就要定义泛型。其实<>就是用来接收泛型的。当使用集合时,将集合中要存储的数据类型,作为参数传递到<>中即可。

什么时候定义泛型类呢?

当类中要操作的引用数据类型不确定的时候;

早期是通过定义Object来完成扩展。

现在定义泛型来完成扩展。

例如:

      class Tools<PP>

     {

         privatePP p;

         public void setObject(PPp){

            this.p=p;

          }

         public PP getObject(){

       return p;

       }

     }

1、泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。

2、为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。

3、特殊之处:

静态方法不可以访问类上定义的泛型。

如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。

class Demo<T>{

  public  void print(T t){

    System.out,print(t);

  }

  public  <Q> void print(Q q){

    System.out,print(q);

  }

  public static <W> void method(W w){//此处注意泛型的位置

     System.out.print(w);

  }

} 

泛型定义在接口上

interface Inter<T>{

    publicvoid show(T t);

}

class Outer<T>implements Inter<T>{

    publicvoid show(T t){

        System.out.println(t);

    }

}

泛型的限定

通配符,也可以理解为占位符。

extends E:可以接收E类型或者E的子类型------上限

super E:可以接收E类型或者E的父类型-------下限

上限例子:

publicstaticvoid pringCollection(ArrayList<?extends Persons> al)

{               //存储PersonsPersons的子类--上限

          Iterator<?extends Persons> it= al.iterator();

          while(it.hasNext()){

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

          }

}

占位符例子:

 public static void pringCollection(ArrayList<?>al)//?是占位符

{

      Iterator<?> it= al.iterator();

      while(it.hasNext()){

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

      }

}

----- android培训java培训java博客、java学习型技术博客、期待与您交流! ------

如有疑问:http://edu.csdn.net/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_wangtao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值