JAVA集合类笔记


集合类:

         面向对象的语言对现实事物的体现都是以对象的形式,所以为了方便对象的操作,就得对对象进行存储,集合就是存储对象最常用的方式。

数组和集合的不同点:

l  数组虽然可以存储对象,但长度是固定的;集合长度是可变的。

l  数组可以存储基本类型数据;集合只能存储对象。

l  数组只能存储同一类型;集合可以存储不同类型。

java.util包下的集合类结构:


1)   Collection。一个独立元素的序列,这些元素都股从一条或多条规则。

List必须按照插入的顺序保存元素。

Set不能有重复元素,里面的元素没顺序。

Queue按照排队规则确定对象产生的顺序(通常与插入顺序相同)。

2)   Map。一组成对的“键值对”对象,允许你使用键来查找值。ArrayList允许你使用数字来查找值,因此在某种意义上讲,它将数字与对象关联在了一起。映射表允许我们使用另一个对象来查找某个对象,它也被称为“字典”,因为你可以使用键对象来查找值对象,就像在字典中使用单词来定义一样。Map是强大的编程工具。

Collection接口中的方法:


l  ArrayList:它长于随即访问元素,但是在List的中间插入和移除元素时较慢。 List接口的两个实现类:

l  LinkList:底层使用链表实现,在随机访问方面相对较慢,方便插入和删除操作。

l  Vector:与ArrayList的功能相同,不同点:Vector是线程安全的。

 

迭代器Iterator

         迭代器(也是一种设计模式)的概念可以用于达成目的。迭代器是一个对象,它的工作就是便利并选择序列中的对象,而客户端程序员不必知道或关心该序列底层的结构。此外,迭代器通常被称为轻量级对象:创建它的代价小。

         JAVA的Iterator只能单向移动,只能用来:

1.        使用方法iterator()要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素。

2.        使用next()获得序列中的下一个元素。

3.        使用hasNext()检查序列中是否还有元素。

4.        使用remove()将迭代器新返回的元素删除。

 

注意:如果只是向前遍历List,并不打算修改List对象本身,那么使用foreach()语法更加简洁。

           Iterator还可以移除由next()产生的最后一个元素,所以在调用remove()之前必须先调用next()。

Iterator的并发错误:

import java.util.*;

 

class IteratorDemo

{

         public static void main(String[] args)

         {

                   List a = new ArrayList();

                   a.add(1);

                   a.add(2);

                   a.add(3);

                   Iterator it = a.iterator();

                   while(it.hasNext()) {

                            Object o = it.next();

                            a.add(4);              //同时进行操作时,出现异常

                            System.out.println(o);

                   }

                  

         }

}

 

ListIterator:

l  ListIterator是一个更强大的Interator的子类型,它只能用于各种List类的访问。ListIterator可以进行双向移动。

l  ListIterator可以产生当前位置的前一个和后一个元素的索引,并且可以使用set()方法替换它访问过的元素。

l  可以通过ListIterator()方法产生一个指向List开始处的ListIterator,ListIterator(n)方法创建一个一开始就指向列表索引为n的元素。

Stack:

         “栈”通常是指“后进先出”的容器。

         Linkedlist具有能够直接实现栈的所有功能的方法,因此可以直接将LinkedList作为栈使用。

方法摘要:

 

Set

         Set元素无序存放,不保存重复的元素。查找是Set中最重要的操作,因此通常选择HashSet的实现,它专门对快速查找进行了优化。

1.        TreeSet将元素存储在红-黑树数据结构中。

2.        HashSet使用的是散列函数。

3.        LinkedHashList使用了散列,还是使用了链表来维护元素的插入顺序。

HashSet如何保证元素的唯一性:

         通过HashCode()和equals()方法进行判断。

         如果两个元素的hashcode相同,则进行equals()方法判断。

         如果两个元素的hashcode不同,则直接返回false。

         set集合中删除,包含操作时同样使用这两个方法。)

import java.util.*;

class HashDemo

{

         public static void main(String[] args)

         {

                   Set s = new HashSet();

                   s.add(new Person("a1",2));

                   s.add(new Person("a2",4));

                   s.add(new Person("a4",3));

                   s.add(new Person("a1",2));

                   System.out.println(s);

                   Iterator it = s.iterator();

                   while(it.hasNext()) {

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

                   }

         }

}

class Person

{

         String name;

         int age;

         Person(String n,int a) {

                   name = n;

                   age = a;

         }

         public int hashCode() {

                   return name.hashCode()+age;

         }

         public boolean equals(Object obj) {

                   if(!(obj instanceof Person)) {

                            return false;

                   }else {

                            Person p = (Person)obj;

                            return (this.name.equals(p.name))&&(this.age==p.age);

                   }

         }

}

TreeSet:

         此类保证排序后的 set 按照升序排列元素,根据使用的构造方法不同,可能会按照元素的自然顺序进行排序(参见 Comparable),或按照在创建 set 时所提供的比较器进行排序。

         TreeSet在添加元素的时候会调用comparealbe接口里面的compareTo()方法,所以在添加自定义对象元素的时候需要实现compareable接口。

 

TreeSet构造方法添加比较器Comparator:

n  当Set内部的元素不具有比较性时,或者具备比较性不是所需的时候,这时候需要让容器自身具有比较性。

n  定义实现了Comparator接口的类,并将其对象作为参数传给TreeSet的构造方法。

n  覆盖compare()方法。

 

Map:

         将对象映射到其他对象,Map里面存放的是键值对,不能包含相同的键,一个键只能映射一个值。

1.        增加:

V put(K key,V value)

将指定的值与此映射中的指定键相关联(可选操作)。如果此映射中以前包含一个该键的映射关系,则用指定值替换旧值(当且仅当 m.containsKey(k) 返回 true 时,才能说映射 m 包含键 k 的映射关系)。

返回:

以前与指定键相关联的值,如果没有该键的映射关系,则返回 null。如果该实现支持 null 值,则返回 null 也可表明此映射以前将 null 与指定键相关联。

void putAll(Map<? extends K,? extends V> t)

从指定映射中将所有映射关系复制到此映射中(可选操作)。对于指定映射中的每个键 k 到值 v 的映射关系,该调用的作用等效于在此映射上调用 put(k, v)。如果正在进行此操作的同时修改了指定的映射,则此操作的行为是未指定的。

 

2.        删除:

void clear()

从此映射中移除所有映射关系(可选操作)。

V remove(Object key)

如果存在此键的映射关系,则将其从映射中移除(可选操作)。更正式地说,如果此映射包含满足以下从键 k 到值 v 的映射关系:(key==null ? k==null :key.equals(k)),则移除该映射关系(该映射最多只能包含一个这样的映射关系)。

返回此映射中以前映射该键的值,如果此映射不包含该键的映射关系,则返回 null(如果该实现支持 null 值,则返回 null 也可表明此映射以前将 null 与指定键相关联)。一旦调用返回,则此映射不包含指定键的映射关系。

3.        判断:

boolean containsKey(Object key)

boolean containsValue(Object value)

boolean isEmpty()  如果此映射未包含键-值映射关系,则返回 true。

4.        获取:

V get(Object key) 

返回此映射中映射到指定键的值。如果此映射中没有该键的映射关系,则返回 null。

int size()

返回此映射中的键-值映射关系数。如果该映射包含多个 Integer.MAX_VALUE 元素,则返回 Integer.MAX_VALUE。

Collection<V> values()

Set<Map.Entry<K,V>> entrySet()

Set<K> keySet()

 

l  Hashtable:底层是哈希表数据结构,不可以存入null键null值,该集合是线程同步的,jdk1.0效率低。

l  HashMap:底层是哈希表数据结构,可以存入null键null值,该集和非线程同步,jdk1.2效率高。

l  TreeMap:底层是二叉树数据结构,线程不同步。可以给键排序。

 

泛型:

         泛型的主要目的之一就是用来指定容器要持有什么类型的对象。

简单泛型:

         持有Object类型的对象:

class Holder

{

         private Object a;

         Holder(Object a) {this.a = a;}

}

         Holder可以存储任何类型的对象。通常我们只会使用容器来存储一种类型的对象。

         使用泛型优化上面的代码:

class Holder<T>

{

         private Object a;

         Holder(T a) {this.a = a;}

         public T get() {

                   return a;

         }

}

 

泛型接口:

         泛型可以应用于接口。例如生成器,是一种专门负责创建对象的类。

public interface  Generator<T>

{

         T next();

}

 

泛型方法:

         泛型方法原则:无论何时,只要能做到,尽量使用泛型方法。如果使用泛型方法可以取代将整个类泛型化,那么就应该只使用泛型方法。

public class GenericMethods

{

         public <T> void f(T x) {

                   System.out.println(x.getClass().getName());

         }

         public static void main(String [] args) {

                   GenericMethods gm = new GenericMethods();

                   gm.f("");

                   //输出java.lang.String

         }

}

f()方法的类型参数,是由该方法的返回类型前面动的类型参数列表表明的。

使用泛型类时,必须在创建对象的时候指定类型参数的值,而使用泛型方法的时候,通常不必指明参数类型,因为编译器会为我们找出具体的类型。这称为类型参数推断

 

l  当类指明了泛型类型时,方法上的参数类型以类的泛型为主。

l  静态方法的参数类型不受类的泛型类型的影响,因为静态域在对象创建之前便以加载。

        

泛型限定:

         泛型的通配符:?

         ? extendsE  : 可以接受E类型或E类型的子类。 上限

         ? superE    : 可以接受E类型或E类型的父类。 下限

         代码示例:

class GenericDemo

{

         public static void main(String[] args)

         {

                   ArrayList<? extends Person> a = new ArrayList<? extends Person>();

                   ArrayList<? super Person> a = new ArrayList<? super Person>();

         }

}

 

Collecctions&Arrays

         在java.util包中的ArraysCollections类中都有很多使用方法,可以在一个Collection中添加一组元素。

 

l  Arrays.asList()方法接受一个数组或是一个用逗号分隔的可变参数列表,将其转换为一个List对象。

 

l  Collections.addAll()方法接受一个Collection对象,以及一个数组可变参数列表

l  Collection.addAll()成员方法只能接另一个Collection对象作为参数,因此它不如Arrays.asList()或Collecctions.addAll()灵活,这两个方法使用的都是可变参数列表。  

 

l  易错点:

Arrays.asList()直接输出时,其底层是数组,不能调整尺寸。使用add()或deletet()方法时,将获得Unsuooorted Operation(不支持操作)错误。

使用Arrays.asList()的时候,如果数组中的元素都是对象,数组的元素就直接变成集合中的元素。

    如果数组中的元素是基本数据类型,则集合中的元素为数组。

 

静态导入:

         语法:importstatic 包.类(包.*);

类通过静态导入后,可以直接访问其中的静态方法及静态域,不必再写成.方法.属性 的格式。

 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值