java基础之集合

来源:互联网 发布:时序数据库应用场景 编辑:程序博客网 时间:2024/05/17 05:50

java基础之集合

 (一) 概述
对于数据结构,我想大家并不陌生。而在本质上,java的集合框架就是对数据结构的一个大体上的封装,从jdk1.2推出集合框架的概念以后,我们就没有必要再像以前自己来编写一个链表等数据结构。这个集合框架的概念和c++中的stl一样,可是并没有那么复杂,并且在jdk1.5推出泛型设计后,更是极大的方便了用户,框架也日趋完善。接下来就仔细研究下框架的相关知识,接口主要是谈及设计理念,而具体实现类更多的是使用代码示例完成。
 (二)初识集合
1.这是集合的框架图,从框架图中就可以看出集合类的层次结构,更加有助于学习集合框架。
 (二)4个接口
(1)Collection接口
Collection接口是集合框架的基础,也是单值保存的最大父接口。由于所有单值集合都实现了这个接口,所以熟悉它的方法是必要的。其中方法有:
增加:boolean addAll(Collection<? extends E> c);加入c所含的所有元素。只要加了元素,就返回true
     boolean add(E e);保容器能持有你传给它的那个参数。如果没有把它加进去,就返回false
删除:void clear();删除所有元素
     boolean removeAll(Collection<?> c);
      boolean remove(Object o);
        查找:int size();
     boolean isEmpty();
     boolean contains(Object o);
     boolean containsAll(Collection<?> c);
     Iterator<E> iterator();
     Object[] toArray();
     <T> T[] toArray(T[] a);
     boolean retainAll(Collection<?> c);
(2)list接口
list接口继承于Collection接口,并且对其进行了大量的扩充。使用了基于0的下标,即可以通过位置来访问其中的元素,就像数组一样。它所存储的元素允许重复,并且有序。除了继承的方法之外,它还新添加了基于下标的方法,可是lis本身还是一个接口,所以要想使用,就必须知道这个接口的子类。而最常用的是ArrayList和vector。vector是线程安全的,可是在同步实现上会花费大量时间。所以在线程不同步情况下可以使用ArrayList类,下面会讲解ArrayList类。由下面这些方法也可以看出List接口主要是增加了支持下标的操作方法。
增加:boolean addAll(int index, Collection<? extends E> c);
             void add(int index, E element);
删除:E remove(int index);
改变:E set(int index, E element);
查找:int indexOf(Object o);
     int lastIndexOf(Object o);
             ListIterator<E> listIterator();     ListIterator<E> listIterator(int index);             List<E> subList(int fromIndex, int toIndex);          
(3)set接口
set接口就是集合接口。这里所说的集合与数学中的集合相似。既元素之间互异且无序,简单的说就是元素不能重复。set并不像List那样对Collection进行了大量的扩充,而是完整的继承了下来。并没有新添加方法。它的主要实现类是HashSet和TreeSet。以不同数据结构实现接口正是体现了java中接口与实现相分离的设计。下面将具体阐述HashSet和TreeSet类。
(4)map接口
map接口描述的是映射。映射就是一个元素与另一个元素相互关联,可类比数学中的映射概念。或者说是“键/值对“,键或者值都可以是对象,键必须唯一,键本身就是利用hastSet来实现,而值可以重复。key主要是用于检索关联的值。map接口中的方法如下:
增加:V put(K key, V value);
     void putAll(Map<? extends K, ? extends V> m);
删除:void clear();
     V remove(Object key);
查找:int size();
     boolean isEmpty();
     V get(Object key);
     boolean containsKey(Object key);
     boolean containsValue(Object value);
     Collection<V> values();
     Set<K> keySet();
     Collection<V> values();
     Set<Map.Entry<K, V>> entrySet();
 (二)具体实现
       1. Lisy接口具体实现类
(1)ArrayList类
ArrayList类封装了一个动态再分配的对象数组,动态以为着可根据需要动态的增加数组长度,当超过原始大小时,会动态的增加数组长度,当元素被删除时,可以缩小数组。而ArrayList类的数组默认大小是10,当然可以在构建ArrayList类时指定默认大小,也可以通过ensureCapacity方法来人工增加ArrayList的容量。但是在分配也有自己的问题,因为再分配会话较多的时间,所以会影响性能,所以在事先知道会存储大量数据时,一次性就扩大它的容量是较好的做法。接下来就举例:
//三种构造方法ArrayList<String> list1=new ArrayList<>();//默认构造方法ArrayList<String> list2=new ArrayList<>(list1);//用list1的数据来初始化list2ArrayList<String> list3=new ArrayList<>(15);//指定初始化时的容量//增加:list1.ensureCapacity(15);list3.add(0, "A");list3.add("B");//Colection的add方法语义已经改变,在末尾增加数组list3.add(2,"C");list3.add("D");System.out.println("list3-->"+list3);//addAll也同样的方法//结果:list3-->[A, B, C, D]//删除list3.trimToSize();//把ArrayList的大小和实际所含元素的大小设置一致list3.remove("A");list3.remove(0);System.out.println("list3-->"+list3);System.out.println("list3-->"+list3.size());//结果:list3-->[C, D]//改:list3.set(0, "C1");System.out.println(list3);//结果:[C1, D]//查:System.out.println(list3.get(0));System.out.println(list3.contains("C1"));ListIterator<String> lst=list3.listIterator();while(lst.hasNext()){System.out.println(lst.nextIndex()+"-->"+lst.next());}//结果:C1 true 0-->C1 1-->D
(2)LinkedList类
LinkedList类是与ArrayList类相互补的类,底层采用双向循环链表结构,适用于频繁的增加或者删除数据的类,而像快速检索数据则需要使用ArrayList类。
   LinkedList<Integer> list = new LinkedList<Integer>();          System.out.println(list.size());            /* 向list中添加元素 */          list.add(1);          list.add(2);          list.add(3);          list.add(5);          list.add(4);                    System.out.println(list.size());            /* 遍历list */          for (Integer integer : list) {              System.out.println(integer);          }            /* 获取第一个元素 ,即header的next域*/          System.out.println("第一个元素是:" + list.getFirst());                    /*获取最后一个元素,即header的previous域*/          System.out.println("最后一个元素是:"+list.getLast());      }  

       2 Set接口具体实现类
(1)HashSet类
HashSet类是set接口的子类,该容器所包含的元素不能重复且无序,实际上HashSet是基于HashMap来实现的,通过查看源代码可以知道,HasetSet方法大部分是通过调用hashMap的方法来实现,HashSet 中的包含元素实际上由 HashMap 的 key 来保存,而 HashMap 的 value 则存储了一个 PRESENT,它是一个静态的 Object 对象。 
// 使用 HashMap 的 key 保存 HashSet 中所有元素   private transient HashMap<E,Object> map;    // 定义一个虚拟的 Object 对象作为 HashMap 的 value    private static final Object PRESENT = new Object();  
HashSet采用散列法,散列优点在于即使存在一个非常大集合数据,它的的基本操作如add,remove,contains,size等方法,它们的运行时间可以保持不变。所以如果不关心元素的顺序,并且想要快速的查找元素,就可以使用HashSet类。还有一点需要注意的是当我们试图把某个类的对象放入 HashSet 中保存时,重写该类的 equals(Object obj) 方法和 hashCode() 方法很重要,而且这两个方法的返回值必须保持一致。因为HashSet在比较是不仅比较了equals,而且还比较了hashcode方法。
在构造hashSet类时,其中个构造方法是public HashSet(int initialCapacity, float loadFactor),第一个参数是初始容量,如果事先知道容量,这样会比较好,但是我们并不是总能知道需要装多少个元素,当元素太多,散列太满,为避免散列冲突,这时就需要再散列,如果要对散列表再散列,就需要创建一个容量更多的表,并将所有元素插入到这个新表中,然后丢弃原米的表。装填因子(第二个参数)决定何时对散列表进行离散。例如,如果装填回子为0 .75 (默认值),而表中超过75% 的位置已经填人元素,这个表就会用双倍的容量自动地迸行再散列。接下来我将一一举例如何使用:
class Person{private String name;private int age;public Person(String name, int age) {super();this.name = name;this.age = age;}public int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}public boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Person other = (Person) obj;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}public String toString() {return "Person [name=" + name + ", age=" + age + "]";}}

public class HashSetTest {public static void main(String[] args) {HashSet<Person> set=new HashSet<>();//增加:set.add(new Person("lkx3",15) );set.add(new Person("lkx2", 16));set.add(new Person("lkx1",17));Iterator<Person> it=set.iterator();while(it.hasNext()){System.out.println(it.next());}//删除:set.remove(new Person("lkx1",17));//查找System.out.println(set.isEmpty());System.out.println(set.contains(new Person("lkx1",17)));}}
(2)TreeSet类
TreeSet是数集,与散列集十分相似,但是又有改进,那就是数集是一个有序集合,以任意顺序插入元素,数集将自动或者按照指定的比较器来对插入元素进行排序,然后在遍历时将按照顺序输出。数集的底层数据结构采用的是红黑树,在添加一个元素的事情上,数集所花费的时间要比散列集多。
前面已经讲过数集里的元素有序,当传入一个对象时,为了排序,插入的类需要实现comparable接口,以便按照指定的顺序排序。在java内置的类里,String 类就实现了 Comparable接口,这个类的compareTo方法依据字典序( 有时称为词典序)对字符串进行比较。而采用实现Comparable接口来排序也有一定的局限,如果在这个数集里用这种排序规则,而在另一个树集中采用那个规则,就有了局限。所以数集里有个构造方法,其参数就是一个Comparator接口。所以可以实现这个接口里的compare方法,数集将按照这个方法进行排序。示例如下:
//实现比较接口,进行排序class Order implements Comparable<Order>{private String name;private int orderCount;public Order(String name, int orderCount) {this.name = name;this.orderCount = orderCount;}public int compareTo(Order order) {if(orderCount<order.orderCount){return -1;}else if(orderCount==order.orderCount){return 0;}else {return 1;}}public String toString() {return "Order [name=" + name + ", orderCount=" + orderCount + "]";}}public class TreeSetTest {public static void main(String[] args) {TreeSet<Order> set=new TreeSet<>();set.add(new Order("col",10));set.add(new Order("lkx",5));set.add(new Order("ccc",15));Iterator<Order> it=set.iterator();while(it.hasNext()){System.out.println(it.next());}}
       3 map接口具体实现类
(1)HashMap类
HashMap类使用散列表实现Map接口,与上述HashSet类似,它允许使用 null 值和 null 键。他也有与hashSet类似的构造函数,初始容量和加载因子,意思也差不多。注意它不是线程同步的。
public class HashMapTest {public static void main(String[] args) {HashMap<String,Double> hm=new HashMap<>();hm.put("lkx1", new Double(323.4));hm.put("lkx2", new Double(123.22));hm.put("lkx3", new Double(1245.2));//返回键值集视图,当然还有映射中键集的视图(public Set<K> keySet())//值集视图(public Collection<V> values() )Set<Entry<String,Double>> set=hm.entrySet();Iterator<Entry<String,Double>> it=set.iterator();//显示while(it.hasNext()){Entry<String,Double> em=(Map.Entry<String,Double>) it.next();System.out.println(em.getKey()+"-->"+em.getValue());}}}
(2)TreeMap类
TreeMap类是基于红黑树实现的。TreeMap提供了按排序顺序存储键/值的有效手段,同时允许快速检索,应该注意的是,不想散列映射,树映射保证了它的元素按照关键在升序排序。其中也有一个构造方法与TreeSet一样。TreeMap(Cpmparator comp 提供比较器。
public class TreeMapTest {public static void main(String[] args) {TreeMap<Integer, String> tm=new TreeMap<>();tm.put(new Integer(3200), "kk");tm.put(new Integer(5000), "sss");tm.put(new Integer(1500),"sws");Collection<String> col=tm.values();Iterator<String> it=col.iterator();while(it.hasNext()){System.out.println(it.next());}}}

参考资料:
《java 核心技术卷一》
《java 从入门到精通》
                                             
0 0
原创粉丝点击