集合框架

来源:互联网 发布:万方数据库期刊查询 编辑:程序博客网 时间:2024/06/05 19:35

6.3集合框架

6.3.1简述

1、由来

对象用于封装特有数据,对象多了需要存储,且对象的个数不确定,于是 SUN公司专

门设计了一组类,这组类因内部的数据结构不同,不断向上抽取,就形成了各种不同的具体容器,即容器类,这些容器共同组成了集合框架(Collection Framework)。集合框架包含在java.util 包中。

任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。

2、 从体系上讲,集合框架可分为两种:

⑴、Collection接口:

①、Set:集,无序性,无重复

②、List:以线性方式存储,只能在头或尾添加,或者在指定的位置后面插入新对象

⑵、Map接口。

3、整个框架如下图:

4、特点

①、集合用于存储对象。

②、集合的长度是可变的

③、集合中不可以存储基本数据类型

5、集合与数组的区别

①、数组的长度是固定的;集合长度是可变的。

②、数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。

③、数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。

6.3.2 Collection

java.util.collection接口是描述Set和List集合类型的根接口,

1、集合操作的常见方法,包括:

以代码的形式介绍:

import java.util.ArrayList;

import java.util.Collection;

import java.util.Iterator;

publicclass CollectionDemo {

    publicstaticvoidmain(String[] args) {

        Collection c1 = new ArrayList();

        Collection c2 = new ArrayList();

        // 1、添加元素(add)

        c1.add("hufei1");

        c1.add("hufei2");

        Sop(c1);// 测试代码

        c2.add("hufei3");

        c2.add("hufei4");

        c2.add("hufei1");

        c1.addAll(c2);// 将c2中的元素添加到c1中

        Sop(c1);// 测试代码

        // 2、删除元素

        c1.remove("hufei1");//删除hufei1元素,同时改变了集合的长度

        Sop(c1);// 测试代码

        c1.clear();// 清空集合

        Sop(c1);// 测试代码

        c1.removeAll(c2);// 将俩个集合中的相同的元素从调用该的集合删除

        Sop(c1);// 测试代码

        // 3、判断元素

        Sop(c1.contains("hufei2"));//测试代码

        Sop(c1.containsAll(c2));// 测试代码

        Sop(c1.retainAll(c2));

//取交集,保留俩集合相同的元素,除此之外还有isEmpty(),containAll(collection c),

        // 4、获取元素(Iterator)

        // 下面的代码会详述

    }

}

2、关于迭代器

、定义:按次序一个一个的获取集合中的所有对象

、使用迭代器的基本机制:

集合—>迭代器—>hasNext()测试—真—>连续调用next()方法—>对象
                                      —假—>不再有对象有效

、迭代器原理:在集合框架中,容器种类很多,每种容器的数据结构都有自己的特点,而要取出其中的元素,就必须依赖于具体容器来实现迭代器,从而创造自己独有的迭代器,这个迭代器必须做俩件事,判断有没有元素和取出元素,即hasNext()和next(),把这些容器的独有迭代器向外抽取就形成了Iterator接口。他是对所有的Collection容器进行元素取出的公共接口
    接上的代码:

//与forEach相结合

        Iteratorit = c1.iterator();

        for(it.hasNext()){

        //以上代码也可写成for(Iterator it = c1.Iterator();it.hasNext())

        Sop(it.next());

        }

        //与while相结合

        Iteratorit = c1.Iterator();

        while(it.hasNext()){

        Sop(it.next());

        //它与for循环的区别在于在代码结束后,引用还留在内存中,所以是否用它视

        //情况而定

        }

6.3.3 List

1、常见方法

⑴、常见方法的特点:可以操作角标

⑵、以代码的形式介绍方法:

 //1、添加元素(add)

    list.add("hufei1");

    list.add("hufei2");

    list.add("hufei3");

    Sop(list);

    //2、删除元素

    Sop(list.remove(0));//删除角标为2的元素,同时改变了集合的长度

    //3、修改元素

    Sop(list.set(1, "hufei4"));//

    //4、获取元素

    Sop(list.get(0));//测试代码

    //5、获取子元素

    Sop(list.subList(1, 2));

//返回指定的 角标1(包括 )和 角标2(不包括)之间的子元素

2、ListIterator接口

⑴、list获取元素的方法

//获取元素的方法一

        Iterator it = list.Iterator();

          for(it.hasNext()){

          Sop(it.next());

          }

        //获取元素的方法二

          for(int x= 0; x < List.size()); x++){

         Sop(list.get(x));//list独有的方法

        }

⑵、由来(利用代码解释)

import java.util.ListIterator

import java.util.ArrayList;

import java.util.List;

publicclass ListIterator {

    publicstaticvoidmain(String[] args){

    List list = new ArrayList ();

           Iteratorit = list.iterator();

           while(it.hasNext()){

              Object obj = it.next();//返回Object的原因是add方法添加的就是Object对象

              if(obj.equals("hufei2"))

                  list.add("hufei4");//这样做会发生ConcurrentModificationException异常,因为list与Iterator同时发生,

             else

     Sop(obj);

       //以上代码容易出现异常,

        }

    }

}

由于在迭代器过程中,使用集合操作元素,容易出现异常,所以可以使用Iterator接口的子类接口ListIterator来完成在迭代中对元素进行更多的操作。

以上迭代器的代码可改为以下代码:

ListIterator it = list.listIterator();

        while(it.hasNext()){

           Object obj = it.next();

           if(obj.equals("hufei2"))

               it.add("hufei5");

           Sop(obj);

3、ListIterator的常见方法          

①、ListIterator可以在迭代过程中实现增删改查,而且只有List集合具备该迭代功能

②、hasNext();以正向遍历列表时,如果列表迭代器有多个元素,则返回true

③、hasPrevious();如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。

④、nextIndex() 返回对 next 的后续调用所返回元素的索引。

4、List常用子类

①、Vector:内部是数组数据结构,是同步的,Vector只保存对象的引用,而不是实际对象

②、ArrayList:内部是数组数据结构,是不同步的,替代了Vector,由于空间连续,所以查询的速度快。

import java.util.ArrayList;

import java.util.Iterator;

publicclass ArrayListTest {

   publicstaticvoid main(String[] args) {

       ArrayList al = new ArrayList();//初始容量为 10的空列表

       al.add(new Person("zhangsan1",21));

       al.add(new Person("zhangsan2",22));

       al.add(new Person("zhangsan3",23));

       al.add(new Person("zhangsan4",24));

       al.add(5);//自动装箱,基本数据类型赋值给引用数据类型al.add(5)

//相当于al.add(new Integer(5))

       Iterator it = al.iterator();

       while(it.hasNext()){

       //Sop(it.next().getName);失败的原因:在add的时候,已经自动将

Person提升为Object类型了,但Object中没有getName方法         

//Sop(((Person)it.next()).getName()+"::"+((Person)it.next()).getAge());//在里面放俩个next,它会指向下一个数据,会输出zhangsan1::22 zhangsan 3 : :24,会出现问题,所以代码应该如下:

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

//多次调用it.next()先给它取个名字

         Sop(p.getName()+"::"+p.getAge());

       }

  }

}

将以下代码放置于另一个java文件中

publicclass Person{

  privateStringname;

    privateintage;

    public Person(String name,int age) {

      super();

      this.name = name;

      this.age = age;

   }

   public Person() {

      super();

   }

   public String getName() {

      returnname;

   }

   publicvoidsetName(String name) {

      this.name = name;

   }

   publicintgetAge() {

      returnage;

   }

   publicvoidsetAge(int age) {

      this.age = age;

  }

}

③、LinkedList:内部是链表数据结构,是不同步的。增删元素速度快

LinkedList常见方法

 

jdk1.6以前

jdk1.6

共同点

区别

添加

addFirst

offerFirst

将指定元素插入此列表的开头

 

addLast

offerLast

在此列表末尾插入指定的元素。

 

获取

getFirst

peekFirst

获取元素,但不删除

如果链表为空,则抛出NoSuchElementException

getLast

peekLast

如果链表为空,返回null

删除

removeFirst

pollFirst

获取元素并删除,还返回删除的元素

如果链表为空,则抛出NoSuchElementException

removeLast

pollLast

如果链表为空,返回null

面试题

import java.util.Iterator;

import java.util.LinkedList;

class Queue{

    privateLinkedListlink;

    Queue(){

        link = new LinkedList();

    }

    publicvoid myAdd(Object obj){

        link.add(obj);

    }

    publicObject myGet(){

        returnlink.removeLast();//队列:先进先出(FIFO

        //return link.removeFirst();//堆栈:先进后出(FILO

    }

    publicboolean isNull(){

        returnlink.isEmpty();

    }

}

publicclass InterviewTest {

    /*

     * 请使用LinkedList来模拟一个堆栈或者队列数据结构容器,

     * 即描述这样一个容器,给使用对象提供一个容器完成这俩种结构的一种

     *   堆栈:先进后出(FILO

     *   队列:先进先出(FIFO

     */

    publicstaticvoidmain(String[] args) {

        Queue q = new Queue();

        q.myAdd("hufei1");

        q.myAdd("hufei2");

        q.myAdd("hufei3");

        while(!q.isNull()){

           Sop(q.myGet());

        }

    }

}           

                                    

6.3.4 Set  

1、其方法与collection一致

2、特点: 元素不可重复,无序。

3、HashSet:

⑴、哈希表:是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射方法叫做散列方法,存放记录的数组叫做散列表。

 ⑵、哈希方法的构造方法: 除留余数法:取关键字被某个不大于哈希表毕表长m的数p除后所得余数为哈希地址。

⑶、冲突:

         ①含义:对于不同的关键字可能得到同一哈希地址

         ②哈希表确定关键字是否相同的方法:先判断的是俩个元素的哈希值是否相同。如果相同,在判断俩个对象的内容是否相同。判断哈希值相同,就是判断对象的hashCode()方法,判断内容相同,用的是equals方法,当然,如果哈希值不同,是不需要判断equals的

        ③处理冲突的方法:链地址法

      ⑷、LinkedHashSet:哈希表与链表的实现

      ⑸、代码示例:

import java.util.HashSet;

import java.util.Iterator;

import java.util.LinkedHashSet;

publicclass SetDemo {

publicstaticvoidmain(String[] args) {

        HashSet<Person> hs  = new HashSet<Person>();

        /*

        * HashSet集合数据结构是哈希表,所以存储的时候,使用的元素

* 的hashCode方法来确定位置,如果位置相同,在通过元素的

* equals确定是否相同。

        */

        hs.add(new Person("hufei1",21));

        hs.add(new Person("hufei2",22));

        hs.add(new Person("hufei2",22));

         /* 为什么打印的结果是22::hufei2 22::hufei2,HashSet的元

* 素不是不可以相同的吗?因为Person类继承的是Object类的

* 法,于是使用的元素的hashCode方法来确定位置,而位置相同,

* 再利用元素的equals来确定,可是在Object中equals方法比较

* 的是地址值,每new一个对象,其地址值就不一样,所以打印的

* 结果是这个样子的,所以要根据Person自己的特点,创建自己的

* hashCode和equals方法

         */

        hs.add(new Person("hufei3",23));

        hs.add(new Person("hufei4",24));

       Sop(hs.remove(newPerson("hufei1",21))); 

        Iterator<Person> it =hs.iterator();

          while(it.hasNext()){

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

          Sop(p.getAge()+"::"+p.getName()); 

          }

          Sop("以上为HashSet的代码示例的结果,以下为LinkedHashSet的代码示例的结果");

          HashSet<Person>hs1  = new LinkedHashSet<Person>();

//即要保证有序,又要保证唯一就用LinkedHashSet

          hs1.add(new Person("hufei1",21));

          hs1.add(new Person("hufei2",22));

          hs1.add(new Person("hufei3",23));

          Iterator<Person> it1 =hs1.iterator();

          while(it1.hasNext()){

             Person p1 =(Person)it1.next();

            Sop(p1.getAge()+"::"+p1.getName());

          }

  }

}

4、TreeSet

      排序方法一:让元素自身具备比较功能,然后实现Comparable接口,覆盖compareTo方法。

publicclass TreeSetDemo {

    publicstaticvoid main(String[] args) {

         Demo_1();

//只是为了说明TreeSet可以对Set集合中的元素进行指定的排序

         TreeSet<Person> ts = new TreeSet<Person>();

         ts.add(new Person("zhangsan",28));

         ts.add(new Person("wangwu",24));

         ts.add(new Person("lisi",29));

         ts.add(new Person("zhaoliu",30));

         Iterator<Person> it =ts.iterator();

         while(it.hasNext()){

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

           Sop(p.getName()+":::"+p.getAge());

         }

  }

  privatestaticvoidDemo_1() {

      TreeSet<String> ts = new TreeSet<String>();

         ts.add("yaner");

         ts.add("hufei");

         ts.add("meiqi");

         ts.add("mama");

         Iterator<String> it =ts.iterator();

         while(it.hasNext()){

           Sop(it.next());

         }

  }

}

      排序方法二;如果不按照对象中的自然顺序进行排序,或者不具备自然顺序时,可以使用这种方式,即让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法,将该对象作为参数传递给TreeSet集合的构造方法。

publicclass ComparatorByNameimplements Comparator {

      int compare(Object o1, Object o2) {

              Personp1 = (Person)o1;

             Person p2 = (Person)o2;

             int temp = p1.getName().compareTo(p2.getName());

             return temp==0?p1.getAge()-p2.getAge():temp;

      }

  }

}   

以上代码的Person类的代码:

publicclass Personimplements Comparable{

  privateStringname;

    privateintage;

    public Person(String name,int age) {

      super();

      this.name = name;

      this.age = age;

   }

   @Override

  publicint hashCode() {

      returnname.hashCode()+age*45;//可以乘任意数值

  }

  @Override

  publicboolean equals(Object obj) {

      if(this==obj){

          returntrue;

      }

      if(!(objinstanceof Person)){

          Sop("类型不符");

      }

      Person p = (Person)obj;//类型强转

      returnthis.name.equals(p.name);

  }

  publicPerson() {

      super();

   }

   public String getName() {

      returnname;

   }

   publicvoidsetName(String name) {

      this.name = name;

   }

   publicintgetAge() {

      returnage;

   }

   publicvoidsetAge(int age) {

      this.age = age;

  }

  @Override

  publicint compareTo(Object o) {

//返回的是int的原因:compareTo返回的正数、负数或零

      Person p = (Person)o;

//------------以下为年龄排序----------------------

//  if(this.age>p.age)

//        return 1;

//  if(this.age>p.age)

//         return -1;

//   return this.name.compareTo(p.name);

//------------以上代码太烂------------------------------       

//  int temp = this.age-p.age;

//  return temp == 0 ? this.name.compareTo(p.name):temp;

//------------以姓名排序--------------------------

      int temp =this.name.compareTo(p.name);

      return temp == 0 ?this.age-p.age:temp;

  }}

6.4Map

6.4.1 Map概述

1、Map的特点

⑴、Map:一次添加一对元素,Collection一次添加一个元素。

     ⑵、Map也称双列集合,Collection也称单列集合,在集合框架中并列存在

     ⑶、其实Map集合存储的就是键值对,Map集合中键必须保证唯一性。

     ⑷、Map集合没有直接取出元素的方法,而是先转成Set集合,在通过迭代获取元素

⑸、Map存储元素使用put方法,Collection使用add方法。

2、常用方法:

     ⑴、添加

        valueput(key,value);返回前一个和key关联的值,如果没有就返回null。

putAll(Map<? extends K,? extendsV> m)

  ⑵、删除

        value clear();清空map集合。

        valueremove();根据指定的key翻出这个键值对。

     ⑶、判断

        booleancontainKey(key);

        booleancontainValue(value);

        booleanisEmpty();

     ⑷、获取

        valueget(key):通过键获取值,如果没有该键返回null,当然也可以通过返回null,来判断是否包含指定键。

        intsize():获取键值对的个数。

     ⑸、values方法

3、重点方法:获取所有的键值对的方式

⑴、Set<k> keySet

          privatestaticvoidmethod_2(Map<Integer, String> map) {

               Set<Integer>keySet = map.keySet();

               Iterator<Integer>it = keySet.iterator();

               while (it.hasNext()) {

                   Integer key = it.next();

               Stringvalue = map.get(key);

               Sop(key+ "=" + value);

               }

      }

   ⑵、Set<Map.Entry<k,v>>entrySet:提倡用这种方法

将map集合中的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry。Entry其实就是Map中的一个static内部接口。为什么要定义在内部呢?因为只有有了Map集合,有了键值对,才会有键值的映射关系。关系属于Map集合中的一个内部事物。而且该事物在直接访问Map集合中的元素。

privatestaticvoidmethod_3(Map<Integer, String> map) {

           Set<Map.Entry<Integer,String>> entrySet = map.entrySet();

           // public static interfaceMap.Entry<K,V>:Entry<K,V>是Map内部接口

           Iterator<Entry<Integer,String>> it = entrySet.iterator();

           while (it.hasNext()) {

               Map.Entry<Integer,String> me = it.next();

               Integerkey = me.getKey();

               Stringvalue = me.getValue();

               Sop(key+ "=" + value);

           }

}

 4、 map常用的子类:

Map皆空常用的实现类有Hashtable,HashMap和TreeMap,通常建议使用HashMap结合实现Map集合,因为HashMap类实现Map集合对于添加和删除映射效率更高.HashMap是给予哈希表的Map接口的实现,HashMap通过哈希吗对其内部的映射关系进行快速查找。

而TreeMap中的映射关系存在一定的顺序,如果希望Map集合中的对象存在一定的顺序,应该使用TreeMap类实现Map集合.Map和Set很像,Set底层就是使用了Map集合。

注意:面试时,问HashMap和Hashtable的区别:

           HashMap:允许null作为键,null作为值

       Hashtable:不允许null作为键,null作为值

 ⑴、Hashtable:内部结构是哈希表,是同步的,不允许null作为键,null作为值

           Properties:用来存储键值对型的配置文件的信息,可以和IO技术结合

     ⑵、HashMap:内部结构是哈希表,不是同步的。允许null作为键,null作为值。

          ①、HashMap代码示例②

publicclass HashMapDemo {

  //需求:将学生对象和学生的归属地通过键与值存储到map集合中

  publicstaticvoidmain(String[] args) {

      HashMap<Student, String> hm = new HashMap<Student, String>();

      hm.put(new Student("hufei", 23),"九江");

      hm.put(new Student("zhouxia", 21),"宁波");

      hm.put(new Student("hubing", 21),"宜春");

      hm.put(new Student("wuxuan", 22),"上饶");

      hm.put(new Student("zhouxia", 21),"浙江");

      // Set<Student> keySet = hm.keySet();

      // Iterator<Student> it = keySet.iterator();

      Iterator<Student> it =hm.keySet().iterator();

      while (it.hasNext()) {

          Student key = it.next();

          String value = hm.get(key);

          Sop(key.getName() + ":" + key.getAge() +"--" + value)

      }

      // -----------------注---------意---------------------------

      // hm.put(new Student("zhouxia", 21), "宁波")和hm.put(newStudent ("zhouxia", //21), "浙江")的键相同但却没有被覆盖,原因是hash有自己的判断标准,所以我们要自定义//我们的判断规则,只需要在Person类中通过hashcode和equals方法建立规则就行

         }

}

②、LindkedHashMap代码示例

publicclass LinkedHashMapDemo {

//HashMap是无序的,如何有序?有序是指怎么存入就怎么取出。要有序只需利LinkedHashMap

    publicstaticvoidmain(String[] args) {

        HashMap<Integer, String> hm = new LinkedHashMap<Integer, String>();

        hm.put(1, "九江");

        hm.put(78, "宁波");

        hm.put(6, "宜春");

        hm.put(22, "上饶");

        Iterator<Map.Entry<Integer,String>> it = hm.entrySet().iterator();

        while (it.hasNext()) {

           Map.Entry<Integer, String> me= it.next();

           Integer key = me.getKey();

           String value = me.getValue();

           Sop(key + "=" + value);

        }

    }

}

     ⑶、TreeMap:内部结构是二叉树,不是同步的,可以对Map集合中的键值对进行排序

publicclass TreeMapDemo {

  //需求:将学生对象和学生的归属地通过键与值存储到map集合中

  publicstaticvoid main(String[]args) {

      TreeMap<Student, String> tm = new TreeMap<Student, String>(new CompareByName());

      tm.put(new Student("hufei", 23),"九江");

      tm.put(new Student("zhouxia", 21),"宁波");

      tm.put(new Student("hubing", 22),"宜春");

      tm.put(new Student("wuxuan", 22),"上饶");

      tm.put(new Student("zhouxia", 21),"浙江");

      Iterator<Map.Entry<Student,String>> it = tm.entrySet().iterator();

      while (it.hasNext()) {

          Map.Entry<Student, String> me =it.next();

          Student key = me.getKey();

          String value = me.getValue();

          Sop(key.getName() + ":" + key.getAge() +"---"+ value);

      }

  }

}

6.4.2 工具类  

   1、Collections

collections是集合框架的工具类 里面的方法都是静态的方法

      ⑴、排序:用俩个mySort方法来写俩个sort()方法源码

import java.util.ArrayList;

import java.util.Collections;

import java.util.Comparator;

import java.util.List;

publicclass CollectionsDemo {

    publicstaticvoidmain(String[] args) {

        List<String> list = new ArrayList<String>();

        list.add("ad");

        list.add("ter");

        list.add("fae");

        list.add("dsjfa");

               Collections.sort(list);

               mySort1(list);

               Sop(list);

               mySort2(list,new ComparatorByLength());

               Collections.sort(list,new ComparatorByLength());

               Sop(list);

}

         privatestatic<T>void mySort2(List<T> list,Comparator<?super T> comp){

            for (int i = 0; i < list.size() - 1; i++) {

               for (int j = i + 1; j < list.size(); j++) {

                   if (comp.compare(list.get(i), list.get(j)) >0) {

                       Collections.swap(list,i, j);

                   }

               }

           }

        }

        privatestatic<Textends Comparable<?super T>>void mySort1(List<T> list){

           for (int i = 0; i < list.size() - 1; i++) {

               for (int j = i + 1; j < list.size(); j++) {

                   if (list.get(i).compareTo(list.get(j)) > 0){

                       // T temp = list.get(i);

                       // list.set(i, list.get(j));

                       // list.set(j, temp);

                       // -----以上的代码是以下代码的原码-----------------

                       Collections.swap(list,i, j);

                       }

                   }

                }

            }

}

⑵、折半

int index = Collections.binarySearch(list,"add");

    Sop(index);// 其结果是:-2,什么意思?(-(插入点)-1)

⑶、最值

String max1 =Collections.max(list);

        Stringmax2 = Collections.max(list, new ComparatorByLength());

        Sop(max1);

   Sop(max2);

⑷、逆序   

        ①、逆序的源码

TreeSet<String>ts = new TreeSet<String>(new ComparatorByLength(){

public intcomparator(String s1, String s2) {

               int temp = s2.length()-s1.length(); 

         return temp == 0 ? s2.compareTo(s1) : temp;

 }

 });

②、逆序排序

TreeSet<String>ts = new TreeSet<String>(Collections.reverseOrder());

③、根据自己定义的比较器进行逆序排序

        TreeSet<String>ts = new TreeSet<String>( Collections.reverseOrder(new ComparatorByLength()));

⑸、替换及其他方法

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

publicclass ReverseOrderDemo

    publicstaticvoidmain(String[] args) {

        List<String> ts = new ArrayList<String>();

        ts.add("fafa");

        ts.add("joi");

        ts.add("eowru");

        ts.add("weu");

      Sop(ts);

// 原理:set(indexOf("fafa"),"hugei")

        Collections.replaceAll(ts, "fafa","hugei");

        Sop(ts);

        Collections.shuffle(ts);// 随机排序,可用于洗牌等。

        Sop(ts);

        Collections.fill(ts, "obj");//将所有的元素换成obj

        Sop(ts);

                }

}

⑹、自定义比较器

import java.util.Comparator;

publicclass ComparatorByLengthimplements Comparator<String> {

    @Override

    publicint compare(String o1, String o2) {

        int temp = o1.length() - o2.length();

        return temp == 0 ? o1.compareTo(o2) : temp;

    }

}

        Collections和Collection有什么区别?
①、Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。它有

两个常用的子接口,List:对元素都有定义索引。有的。可以重复元素。Set:不可以重复元素。

无序。

②、Collections是集合框架中的一个工具类。该类中的方法都是静态的

ⅰ、提供的方法中有可以对list集合进行排序,二分查找等方法。

ⅱ、通常常用的集合都是线程不安全的。因为要提高效率。

ⅲ、如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,

转换成安全的。

   2、Arrays

⑴、二分查找

binarySearch(XX[] a, XX key):使用二分搜索法来搜索指定的XX型数组,以获得指定的值。

binarySearch(XX[]a, int fromIndex, int toIndex, XX key)使用二分搜索法来搜索指定的XX型数组的范围,以获得指定的值。

XX可以是byte、char、double、float、int、long、short等。

⑵、复制指定的数组

copyOf(XX[] original, int newLength)复制指定的数组,截取或用false或0填充(如有必要),以使副本具有指定的长度。

copyOfRange(XX[]original, int from, int to)

XX可以是byte、char、double、float、int、long、short、boolean等

⑶、数组比较

equals(XX[] a, XX[] a2) 如果两个指定的XX型数组彼此相等,则返回true

⑷、排序

sort(XX[] a)对指定的 XX型数组按数字升序进行排序。

sort(XX[] a, intfromIndex, int toIndex)对指定 XX 型数组的指定范围按数字升序进行排序。

XX可以是byte、char、double、float、int、long、short、Object等。

sort(T[] a,Comparator<? superT> c) 根据指定比较器产生的顺序对指定对象数组进行排序。

sort(T[] a, intfromIndex, int toIndex,Comparator<? superT> c)根据指定比较器产生的顺序对指定对象数组的指定范围进行排序。

⑸、toString()

publicclass ArraysDemo {

  publicstaticvoidmain(String[] args) {

      int[] arr = { 4, 2, 5, 3, 1 };

      Sop(Arrays.toString(arr));

      String str = MyToString(arr);

        Sop(str);

}

// toString的经典实现,toString的原代码

    privatestatic String MyToString(int[] arr) {

        if (arr ==null)

           return"null";

        int iMax = arr.length - 1;

        if (iMax == -1)

           return"[]";

        StringBuilder b = new StringBuilder();

        b.append('[');

        for (int i = 0;; i++) {//中间省略了条件判断,提高了效率

           b.append(arr[i]);

           if (i == iMax)

               return b.append(']').toString();

           b.append(", ");

        }

    }

}

⑹、集合与数组互相转换的方法

①将数组转成集合:asList方法

好处:这样可以用集合的方法操作数组中的元素

注意:ⅰ、数组的长度是固定的,所以对数组的增删方法是会出现异常的

{

List<int[]> list = Arrays.asList(arr);

        boolean b = list.contains(1);

                   // list.add(4);这样添加会出现UnsupportedOperationException

              Sop(b);

}

     ⅱ、 如果数组中的元素是对象,那么转成集合时,直接将数组的元素作为集合中的元素进行集合存储;如果数组中的元素是基本数据类型,那么会将该数组作为集合中的元素进行存储

                    List<int[]> list = Arrays.asList(arr);

                        Sop(list);

//打印结果是:[[I@bb0d0d],即list中只有一个元素。

②数组转集合toArray()

toString方法需要传入一个指定类型的数组。该方法返回值有两种形式:一种是Object类型,一种是返回的是<T> T[],而我们一般应该选择后一种。

长度该如何决定?如果长度小于集合的size,那么该方法会创建一个同类型并和集合相同size的数组如果长度大于集合的size,那么该方法会使用指定的数组,存储集合中的元素,其他位置并默认为null 所以建议,长度指定为集合的size

好处:可以对集合中的元素的操作方法进行限定,不允许进行增删。

privatestaticvoidtoArrayDemo(){

        List<String> list = new ArrayList<String>();

        list.add("abc1");

        list.add("abc2");

        list.add("abc3");

        String[] arr = list.toArray(new String[list.size()]);

        Sop(Arrays.toString(arr));

}

   3、方法可变参数

⑴、其实就是一个数组,但是接收的是数组的元素。自动将这些元素封装成数组,简化了调用者的书写。

     ⑵、注意:方法可变参数,必须定义在参数的结尾处,只能有一个。

     ⑶、应用:asList(T... a)方法就用了

     ⑷、代码

publicclass ParamterDemo {

    publicstaticvoidmain(String[] args) {

        // int sum = add(4,5);

        // Sop(sum);

        // int sum1 = add(4,5,4);

        // }

        // private static int add(int i, int j, intk) {

        // return i+j+k;

        // }

        // private static int add(int i, int j) {

        // return i+j;

        // }

        // ---------从可以看出,假如数据量很大,我们可以利用数组------

        int[] arr = { 3, 4, 12, 43, 5 };

        int sum =add(arr);

        Sop(sum);

        // ------但上面的方法依然很怂,我们可以利用jdk1.5新特性 方法可变参数-----

        int newSum =newAdd(arr);

        Sop(sum);

    }

    privatestaticint newAdd(int... arr) {

        int sum = 0;

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

           sum += arr[i];

        }

        return sum;

    }

    privatestaticintadd(int[] arr) {

        int sum = 0;

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

           sum += arr[i];

        }

        return sum;

    }

}

   4、静态导入

其实导入的就是类中的静态成员。

6.4.3 结合总结

1、需要唯一吗 ?

      需要:set

             需要制定顺序;

             需要:TreeSet

             不需要:HashSet

             但是想要一个和存储一致的顺序:LinkedHashSet

      不需要:List

              需要频繁增删吗

              需要:LinkedList

              不需要ArrayList

 2,如何记录每一个容器的结构和所属体系呢?

 看名字:

 List

    |--LinkedList

    |--ArrayList

  Set

    |--TreeSet

    |--HashSet

     后缀名就是该集合所属体系,前缀名就该集合所属结构。

     看到Array:就要想到数组,想到查询快,有角标

     看到link:就要想到链表表,想到增删快,要想到add,get remove+first last方法

     看到hash:就要想到哈希表,想到唯一性,想到元素需要覆盖;hashcode方法和equals方法

     看到tree:就要想到二叉树,想到排序,想到俩个接口Comparator和comparable

而且通常这想法常用的集合都不同步。

3、给非同步的集合加锁

List list = new ArrayList();//非同步的

listMyCollections.synList(list)//返回一个同步的

class MyCollections{

    public List synList(list){

         return new MyList(list);

    }

}

private class MyListimplements List{

  private List list;

  private static final Object lock = newObject();

  MyList(List list){

     this.list = list;

  }

  public boolean add(Object obj){

     synchronized(lock){

        return list.add(obj);

     }

  }

  public boolean remove(Object obj){

     synchronized(lock){

        return list.remove(obj);

     }

  }

对于非同步的集合,在框架中,提供了一个方法将其变成同步。他是synchronizedXxx(xxx<T> c)

6.5 其他对象

6.5.1 System类

publicclass SystemDemo {

    privatestaticfinalStringLINE_SEPARATOR = System.getProperty("line.separator");

    /*

*System类中的方法和属性都是静态的

*常见方法currentTimeMillis():返回当前时间与协调世界时1970年1月1 日午夜之间

*的时间差

     */

    publicstaticvoidmain(String[] args) {

        long l1 = 1372734194222l;// System.currentTimeMillis();

        Sop(l1 / 1000 / 60 / 60 / 24 + LINE_SEPARATOR);

        long l2 = System.currentTimeMillis();

        Sop(l2 - l1);

        // 给系统设置一些属性信息,其他程序都可以用

        System.setProperty("hufei","yaner");

        Dome_1();

    }

    privatestaticvoidDome_1() {

        /*

         *获取系统的属性信息,这些信息是全局的,其他程序都是可以使用的。

         *properties集合中存储的都是String类型的键和值,最好使用它自己的 存储和取出的

*方法来完成元素的操作。

         */

        Properties prop = System.getProperties();// 获取当前的系统属性

        Set<String> nameSet =prop.stringPropertyNames();

        // stringPropertyNames()返回此属性列表中的键集,其中该键及其对应值是字符串

        for (String name : nameSet) {

           String value =prop.getProperty(name);//获取指定键指示的系统属性

           Sop(name + "::" + value);

        }

    }

}

6.5.2 Runtime

publicclass RuntimeDemo {

    /*

     *Runtime:没有构造方法,说明该类不可以创建对象又发现还有静态方法,说明该类应该提

* 供静态的返回该类对象的方法而且只有一个,说明Runtime类使用了单例设计模式。

     */

    publicstaticvoidmain(String[] args)throws IOException,

           InterruptedException {

        Runtime r = Runtime.getRuntime();

        Process p = r.exec("notepad.exeC:\\RuntimeDemo.java");

// 会抛出异常,因为有可能没有该执行文件,即exe文件

        Thread.sleep(5000);

        p.destroy();

    }

}

6.5.3 Math

publicclass MathDemo {

    /*

     *Math:提供了操作数学运算的方法,都是静态方法

* 常用的方法

* ceil:返回大于参数的最小整数

* floor:返回小于参数的最大整数

     *round返回四舍五入的整数

* pow(a,b):a的b次方。

     */

    publicstaticvoidmain(String[] args) {

        for (int i = 0; i < 10; i++) {

           int d = (int) (Math.random() * 10 + 1);

           Sop(d);

        }

Random r =new Random();

          for (int i = 0; i < 10; i++) {

            int d= r.nextInt(10) + 1;

            Sop(d);

        }

        //上面两方法功能一样

        double d1 = Math.ceil(12.46);

        double d2 = Math.floor(12.46);

        double d3 = Math.round(12.46);

        double d4 = Math.pow(10, 5);

        Sop(d1);

        Sop(d2);

        Sop(d3);

        Sop(d4);

       

    }

}

6.5.4 Data

1、日期对象和毫秒值之间的转换。

⑴、毫秒值转成日期对象

①、通过Data对象的构造方法:new Data(timeMillis)

       ②、可以通过setTime设置

为什么要转?因为可以通过Data对象的方法对该日期中的各个字段进行操作

⑵、日期对象转成毫秒值

①、通过getTime设置

为什么要转?因为可以通过具体的数值进行运算。

2、常见方法 日期的比较: after、before、compareTo的方法

publicclass DataDemo {

    publicstaticvoidmain(String[] args)throws ParseException {

        long time = System.currentTimeMillis();

        Sop(time);// 1372749625346

        Date d = new Date();//将当前日期和时间封装成对象

        Sop(d);// Tue Jul 02 15:21:49 CST 2013

        Date d2 = new Date(1372749625346l);//将指定的毫秒值封装成Data对象

        Sop(d2);

}

3、日期对象与日期字符串之间的转换

⑴、 日期对象转成日期字符串:对日期对象进行格式化, 将日期对象转换成日期字符串,使用的是DataFormat类中的format方法

publicclass DataToString {

    publicstaticvoidmain(String[] args) {

        Date d = new Date();

        // 获取日期格式对象,具有着默认的风格。FULL LONG

        DateFormat dateFormat1 = DateFormat.getDateInstance(DateFormat.FULL);

        DateFormat dateFormat2 = DateFormat.getDateTimeInstance(

               DateFormat.FULL, DateFormat.FULL);

        // 如何自定义日期格式风格

        dateFormat2 = new SimpleDateFormat("yyyy--MM--dd");

        String str_data1 =dateFormat1.format(d);

        String str_data2 =dateFormat2.format(d);

        Sop(str_data1);

Sop(str_data2);

   }

⑵、日期字符串转成日期对象:将日期字符串转换成日期对象,使用的是DataFormat类中的

publicclass StringToData {

    publicstaticvoidmain(String[] args)throws ParseException {

        String str_date = "2013-07-02";

        DateFormat dateFormat = DateFormat.getDateInstance();

        dateFormat = new SimpleDateFormat("yyyy-MM-dd");

        Date date = dateFormat.parse(str_date);

        Sop(date);

    }

4、练习 “2012-3-17”到“2012-4-6”中间有多少天

       思路:两个日期相减就O了,必须要有两个可以进行相减运算的数。能减的可以是毫秒值,如何获取?通过Data对象,如何获取data对象?可以将字符串转成data对象。

publicclassDataDemo {

        publicstaticvoid main(String[] args)throws ParseException {

    String str_date1 = "2012-3-17";

    String str_date2 = "2012-4-6";

    DateFormat dateFormat = DateFormat.getDateInstance();

    Date date1 = dateFormat.parse(str_date1);

    Date date2 = dateFormat.parse(str_date2);

    longtime1 = date1.getTime();

    longtime2 = date2.getTime();

    longtime = Math.abs(time1 - time2);

    intday =getDay(time);

    Sop(day);

}

privatestaticintgetDay(long time) {

    intday = (int) (time / 1000 / 60 / 60 / 24);

    returnday;

}

}

6.5.5 Calendar

publicclass CalendarDemo {

  publicstaticvoidmain(String[] args) {

      Calendar c = Calendar.getInstance();

      c.set(1990, 03, 12);

      c.add(Calendar.YEAR, 23);

      c.add(Calendar.MONTH, 3);

      c.add(Calendar.DAY_OF_MONTH, -10);

      String[] months = { "1月","2月""3月""4月",

"5月","6月""7月""8月",

                         "9月","10月","11月","12月" };

      String[] weeks = { "星期一","星期二","星期三","星期四",

"星期五","星期六","星期日" };

      int index = c.get(Calendar.MONTH);

      int index1 = c.get(Calendar.DAY_OF_WEEK);

      sop(c.get(Calendar.YEAR) +"年");

      sop(months[index]);

      sop(c.get(Calendar.DAY_OF_MONTH) +"日");

      sop(weeks[index1]);

  }

}

原创粉丝点击