.Net转Java自学之路—基础巩固篇十三(集合)

集合:

  集合是用于存储对象的一个工具。

  集合与数组的特点

    相同点:都是一个容器

    不同点:

      集合:可以存储对象,只能存储对象,集合长度可变。

      数组:可以存储对象,也可以存储基本数据类型,数组长度固定。

  容器对象有很多种,通过内部的数据结构来区分,数据结构就是一种数据存储方式。

  在不断的将容器对象的相同点抽取的过程中,就出现了集合体系结构,该体系的结构框架称为集合框架。

  最顶层的是一个接口:Collection

  Collection 表示的是一组对象。

迭代器(Iterator):

  Collection集合中对元素的获取方式:hasNext() 判断是否有值、next() 返回迭代的下一个元素、remover() 删除

  集合容器都具备取出方式,取出方式并不是一个方法,因为一个方法并不足以完成取出,取出是由多个方法来完成的,为了方便使用,将这些方法封装称了对象;该对象在描述时,这些功能会直接使用到具体集合中的数据和集合特点。所以这个取出元素的描述类,就定义在集合的内部,也就是一个内部类。

  因为这个类在直接访问集合中的数据,根据集合自身的数据结构特点,将具体的方法都定义完成后,需要将对象对外提供出去让用户使用,所以就暴露了一个方法,来完成对这个内部类对象的访问。

  为了提高扩展性,发现只要是容器,就具备取出功能,但数据结构不同,取出的具体实现一样,这时为了扩展,就抽取了一个接口 Iterator (迭代器)。

Collection coll=new ArrayList();
coll.add("元素1");
coll.add("元素2");
coll.add("元素3");
Iterator iter=coll.iterator();
while(iter.haxNext()){
  iter.next();  
}
//
for(Iterator iter=coll.iterator();iter.haxNext()){
  iter.next();  
}
View Code

  只要是在 Collection 集合体系中,迭代器就是通用的取出方式。

  在进行迭代器使用时,next() 在循环中只能定义一个,定义多个会导致数据错误;当next()没有获取到元素时,会发生NoSushElementException异常。

  用迭代器取出自定义对象的元素时,在 next() 后要进行类型的转换操作。

Collection coll=new ArrayList();
coll.add(new ClassName("元素1"));
coll.add(new ClassName("元素2"));
coll.add(new ClassName("元素3"));
for(Iterator iter = coll.iterator(); iter.haxNext()){
  ClassName cn=(ClassName)iter.next();
  cn.ClassNameMethod();  
}
View Code

集合List:  extends Collection

  该容器的元素有序,存储顺序和取出顺序一致。该集合中的元素都有索引(角标),可以存储重复的元素。

//List常见基本操作
List list=new ArrayList();
//
list.add("元素");
list.add(1,"元素");//指定索引位插入元素,其他元素以此延续
//
list.remover(1);//指定索引位删除元素。被删除的元素会被返回
//
list.set(1,"New元素");//替换指定索引位元素。会返回被修改掉的元素。
//
list.get(1);//获取索引位指定的元素。
list.indexOf("元素");//获取元素第一次出现的位置(索引)
list.subList(int,int);//根据头尾角标获取子列表,返回List集合

列表迭代器:ListIterator

  在进行迭代过程中,若出现了迭代器和容器同时对元素进行操作的情况,很容易引发ConcurrentModificationException(并发修改)异常。对于List集合解决此类异常就用 ListIterator 列表迭代器

  ListIterator 时 Iterator 的子接口。并提供了更多的迭代过程中的操作方法;该迭代器只能用于 List 集合。

//ListIterator 常见基本功能
List list=new ArrayList();
list.add("元素1");
list.add("元素2");
list.add("元素3");
list.add("元素4");

ListIterator lit=list.listIterator();

lit.haxNext();//判断 是否有后一个元素
lit.haxPrevious();//判断 是否有前一个元素
lit.add();//添加
lit.set();//修改
lit.next();//取后一个元素
lit.previous();//取前一个元素

  ArrayList

    底层数据结构是数组结构。实现不同步;jdk1.2 版本 ArrayList 替换 Vector

    ArrayList 对元素的查询快,增、删 慢

    判断元素是否相同时,底层的依据时 equals() 方法;无论时 contains() 还是 remover() 都会去使用 equals() 来判断元素是否相同。所以在往 ArrayList 集合中存储自定义元素时,最好建立该元素特有的判断对象是否相同的依据。也就是覆盖 equals() 方法。

  Vector

    底层数据结构是数组结构。实现同步;jdk1.0版本

    Vector 对元素的增、删、查 都很慢

    elements()方法返回枚举(Enumeration)该功能与迭代器的功能重复;由于枚举(Enumeration)书写麻烦,故被迭代器替换掉。

Vector vt=new Vector();
vt.addElement("元素1");
vt.addElement("元素2");
vt.addElement("元素3");
vt.addElement("元素4");

for(Enumeration ent=vt.elements(); ent.hasMoreElements()){
  ent.nextElement();  
}

  可变长度数组

    ArrayList 内部封装了一个默认长度为10的数组。当超出长度时,集合内部会自动生成一个新的数组;将原数组中的数据复制到新的数组中;ArrayList 新的数组长度是原数组的50%延长;Vector 新的数组长度是原数组的100%延长。

  LinkedList

    底层数据结构是链表结构。实现不同步;jdk1.2 版本;

    LinkedList 对元素的增、删效率高,但查询慢

//特有方法

//
addFirst();
addLast()

//获取元素,集合长度不变
getFirst();
getLast();
//jdk1.6 版本后被下面俩个方法替代。若集合中没有元素,该方法不会抛出异常,而返回null
peekFirst();
peekLast();

//获取被删除的元素,集合长度改变
removeFirst();
removeLast();
//jdk1.6 版本后被下面俩个方法替代。若集合中没有元素,该方法不会抛出异常,而返回null
offerFirst();
offerLast();

集合Set:  extends Collection

  该容器的元素无序;不可以重复元素。Set 接口的取出元素的方法只有迭代器。

  !~ HashSet:

    底层数据结构为哈希表。哈希表这种结构其实就是对哈希表的存储;而且每一个对象都有自己的哈希表。因为 Object 基类中有一个 hashCode() 方法。

    存储自定义对象并且要保证元素的唯一性。HashSet 保证元素的唯一性主要依赖与 hashCode() 和 equals() 方法。

    当元素的哈希值不同时,元素都有自己的独立位置,不需要再判断元素的 equals() 方法。

    当元素的哈希值相同时,这时元素再哈希表中的位置相同,就需要判断一次元素的内容是否相同;调整元素的 equals() 方法进行一致比较;当这俩个元素不相同时,会存储在一个哈希值上;故、需覆盖 hashCode() 和 equals() 方法。而且需要依据对象的特有条件建立 hashCode() 和 equals() 的具体实现。

    判断包含、删除都是依据 hashCode() 。当 hashCode() 相同时,再判断 equals() 方法

  !~ TreeSet:

    对 Set 集合中的元素进行排序。数据结构为二叉树结构;可以提高排序性能。

    自定义元素本身不具备比较性,TreeSet 集合是无法对元素进行排序的。所以在自定义对象时,需要对象具备一个比较功能。而 Java 已经提供了接口,可以让自定义的对象具备比较性。需要实现 Comparable 接口。

    根据比较方法 compareTo() 的返回值来确定元素的唯一性;返回0,则相同。自定义对象需要覆盖 compareTo() 方法。这称为:元素的自然排序。

    如果元素本身的比较方式无法满足应用,那么 可以让集合本身具备比较性,就是定义一个类,实现 Comparator 接口,覆盖 compare() 方法。将Comparator 接口的子类对象作为参数传递给 TreeSet 集合的构造函数即可。

    当元素自身具备比较性,同时 TreeSet 集合也具备比较器,这时以比较器为主。

泛型:

  集合中存储了不同类型的对象,获取时,在运行时容易发生ClassCastException类型转换异常。所以在存储时明确集合要操作的数据类型来避免该异常的发生。

  定义集合时,通过<>来明确元素的类型。这中定义的方式称为:泛型

  优点:

    1、运行时出现的ClassCastException 异常转移到编译时期。

    2、泛型的出现避免了强制转换的麻烦。

  泛型其实时 jdk1.5版本后出现的安全机制。

ArrayList<String> list=new ArrayList<String>();
list.add("元素");
list.add("元素1");

for(Iterator<String> iter=list.iterator();iter.hasNext()){
    iter.next();
}

  泛型的使用其实就是给<>传递实际参数,而这个参数就是一个具体的引用数据类型。

  当类要操作的引用数据类型不确定时,可以使用泛型来定义,也就是定义一个类型参数,将具体的类型作为实际参数传递给<>

  当泛型定义在类上,该泛型作用整个类。建立对象时,就明确了具体类型。那么凡是使用了类上定义的泛型的方法,操作的类也就固定了。

  当类中定义 static 方法时,静态方法不可以直接访问类上的泛型;因为类上的泛型只有通过建立对象才可以明确泛型。那么静态方法若操作的引用数据类型不确定,只能将泛型定义在方法上。在静态方法上定义泛型必须定义在 static 关键字之后。

  当发放中操作的应用数据类型不确定,而且和对应的对象执行的类型也不一定一致。这时就将泛型定义在方法上。

//泛型接口
interface Inter<T>{
  public void method(T t);  
}

泛型通配符:?

  ?  代表任意类型。

public static void method(Collection<?> coll){
  for(Iterator<?> iter=coll.iterator(); iter.hasNext()){
      iter.next();
  }  
}

  定义T只能固定一种类型,定义 ? 可以是任意类型。

  泛型限定:

    ? extends E  接收 E 类型 或 E 的子类型

    ? super E   接收 E 类型 或 E 的父类型

Map集合:

  特点:

    1、双列集合,Collection 是单列集合。

    2、Map 一次存储一对元素,同是键值对的形式,键和值有对应关系。Collection 是一次存储一个元素。

//常见功能:
//
put(k,v);//返回的是v;将键和值存储 Map 集合,当存入相同的 k 时,新值 v 会覆盖原来的值,并返回原来的值。
putAll(map);

//
clear();
remove(k);//根据键删除对应的值,返回被删除的值。

//
containsKey(Object key);
containsValue(Object value);
isEmpty();

//
size();//获取Map 元素个数
get(k);//根据键获取值,还可以判断某个键是否存在的依据。
Collection values();//获取Map 集合中所有的值。
Set keySet();//获取Map 集合中所有的键
Set entrySet();//获取键值对的映射关系。将映射关系封装成对象存入Set 集合

  Map 集合中没有迭代器,迭代器是在 Collection 集合中具备的。

  Map 集合的取出元素的原理,就是将 Map 集合转成 Set 集合,再进行迭代。

  HashTable:

    底层是哈希表数据结构;实现同步。不允许 null 作为键、null 作为值。

    Peoperties:用于配置文件的定义和操作,使用频率高,同时键和值都是字符串。是集合中可以和IO技术相结合的对象。详细见IO篇

  HashMap:

    底层是哈希表数据结构;实现不同步。允许 null 作为键、null 作为值。替代 HashTable

HashMap<Integer,String> hm=new HashMap<Integer,String>();
//若要保证HashMap有序。用LinkedHashMap
HashMap<Integer,String> hm=new LinkedHashMap<Integer,String>();
hm.put(1,"元素1");
hm.put(2,"元素2");
hm.put(3,"元素3");
hm.put(4,"元素4");

hm.size();//元素个数
hm.get(1);//获取键1对应的vaue
hm.remove(1);//删除键1对应的键值对
hm.clear();//清空
hm.containsKey(1);//是否包含键1

//取Map 集合中所有的键值
Set<Integer> hmKey=hm.keySet();//获取所有的键
for(Iterator<Integer> iter=hmKey.iterator(); iter.hasNext()){
  Integer it=iter.next();
  hm.get(it);    
}

//取Map 集合中所有的键值。
Set<Map.Entry<Integer,String>> hmEntry=hm.entrySet();//获取Map 集合中所有的简直对应关系
for(Iterator<Map.Entry<Integer,String>> iter=hmEntry.iterator(); iter.hasNext()){
  Map.Entry<Integer,String> me=iter.next();
  Integer key=me.getKey();
  String value=me.getValue();
}

  TreeMap:

    对Map 集合中的键进行排序。

/* 自定义集合的两种排序方式 */
//一、实现Comparable 接口。重写compareTo() 方法。
TreeMap<Student,String> tm=new TreeMap<Student,String>();
tm.put(new Student("姓名","年龄"),"Str元素");
tm.put(new Student("姓名","年龄"),"Str元素");
tm.put(new Student("姓名","年龄"),"Str元素");

Set<Student> tmkey=tm.keySet();
for(Iterator<Student> iter=tmkey.iterator(); iter.hasNext()){
  Student stu=iter.next();
  tm.get(stu);
}

Class Student implements Comparable<Student>{
  /*
    Code...
  */  
  public int compareTo(Student stu){
    int temp=this.age-stu.age;
    return temp==0?this.name.compareTo(stu.name):temp;
  }
}    

//二、实现Comparator 接口,重写compare() 方法。
TreeMap<Student,String> tm=new TreeMap<Student,String>(new ComparaByName());
tm.put(new Student("姓名","年龄"),"Str元素");
tm.put(new Student("姓名","年龄"),"Str元素");
tm.put(new Student("姓名","年龄"),"Str元素");

Set<Student> tmkey=tm.keySet();
for(Iterator<Student> iter=tmkey.iterator(); iter.hasNext()){
  Student stu=iter.next();
  tm.get(stu);
}

Class ComparaByName implements Comparator<Student>{
  public int compare(Student stu1,Student stu2){
    int temp=stu1.getName().compareTo(stu2.getName());
    return temp==0?new Interger(stu1.getAge()).compareTo(new Integer(stu2.getAge)):temp;
  }
}

  集合框架工具类:

    Collections、Arrays 这两个工具类中的方法都是静态的,不需要创建对象,直接使用类名调用即可。

    Collections:是集合对象的工具类,提供操作集合的工具方法。

Collections.sort(List<T>);//排序,升序
Collections.sort(List<T>,Collections.reverseOrder);//排序,降序
Collections.sort(List<T>,Collections.reverseOrder(Comparator<? super T>));//指定比较器排序,降序
Collections.max();//最大值
Collections.min();//最小值
Collections.binarySearch();//二分查找(折半查找),只作用于List集合
Collections.fill(List<T>,"");//将集合中的元素替换成指定元素
Collections.reverse(List<T>);//将集合元素反转,头尾对调
Collections.swap(List<T>,int,int);//对集合中元素进行位置替换
Collections.shuffle(List<T>);//对集合中的元素进行随机位置置换
Collections.synchronizadList(List<T>);//可以将一个不同步的集合转成同步的List集合。

    Arrays:是数组的工具类。提供操作数组的工具方法。

      Arrays.asList(Array);  数组转成集合

      当数组中的元素是引用类型的数据时,变集合后数组中的元素作为集合中的元素存在。

      当数组中的元素是基本数据类型时,变集合后该数组变成集合中的元素。

      在 Collection 接口中有个集合变数组的方法:toArray();

      ArrayList<String> al=new ArrayList<String>();

      al.toArray(new String[al.size()]);

    jdk1.5版本后,Collection 有个父接口 Iterable 。该接口的出现封装了迭代器 iterator() 方法,并提供了一个增强 for 循环。增强 for 循环只能遍历数组和 Collection 集合。简化迭代器。一般只用于遍历,而不对元素进行操作。

    格式:

      for(元素类型  变量:数组 或 Collection 集合){

        循环体Code;

      }

ArrayList<String> al=new ArrayList<String>();
al.add("元素1");
al.add("元素2");
al.add("元素3");

for(String str:al){
  System.out.println(s);
}

    可变参数:

      在指定数据类型的后面加三个点,其实就是数组类型的参数。

      格式:

        void method(int... arr)

      若函数上有多个参数,可变参数的位置必须是最后一个参数。否则编译失败。

    静态导入:

      为简化集合框架工具类 Collections 的书写,导入一个类名中所有的静态成员 import static java.util.Collections.* 然后直接使用sort()、binarySearch() 等方法来简化Collections.sort()等写法。

      但是当方法名称重复时,必须要指定所属的工具类名 Arrays.toString(arr);

 

posted @ 2018-11-11 18:13  水痕灬  阅读(173)  评论(0编辑  收藏  举报