JAVA菜鸟学习-数据结构与集合框架

JAVA菜鸟学习-数据结构

在Java中的数据结构主要包括以下几种接口和类:

	枚举(Enumeration)

	位集合(BitSet)

	向量(Vector)

	栈(Stack)

	字典(Dictionary)

	哈希表(Hashtable)

	属性(Properties)

任何对象加入集合类后,自动转变为Object类型,所以在取出的时候,需要进行强制类型转换。 任何对象没有使用泛型之前会自动转换Object类型,使用泛型之后不用强制转换。
集合框架的类和接口均在java.util包中。

枚举Enumeration接口

枚举(Enumeration)接口本身不属于数据结构,但它在其他数据结构的范畴里应用很广。 枚举(The Enumeration)接口定义一种从数据结构中取回连续元素的方式
Enumeration接口中定义了一些方法,通过这些方法可以枚举(一次获得一个)对象集合中的元素

使用在诸如Vector和Properties这些传统类、API类应用程序所定义的方法中。

Enumeration声明的方法:

序号方法描述
1boolen hasMoreElements()检测此枚举是否包含更多元素
2Object nextElement()若此枚举对象至少含有一个可提供的元素,则返回此枚举的下一个元素

以下实例演示了Enumeration的使用:

实例

import java.util.Vector;
import java.util.Enumeration;
 
public class EnumerationTester {
 
   public static void main(String args[]) {
      Enumeration<String> days;   //枚举
      Vector<String> dayNames = new Vector<String>();
      dayNames.add("Sunday");
      dayNames.add("Monday");
      dayNames.add("Tuesday");
      dayNames.add("Wednesday");
      dayNames.add("Thursday");
      dayNames.add("Friday");
      dayNames.add("Saturday");
      days = dayNames.elements();    //从vector中枚举元素
      while (days.hasMoreElements()){
         System.out.println(days.nextElement()); 
      }
   }
}

位集合Bitset类

一个Bitset类创建一种特殊类型的数组来保存位值。BitSet中数组大小会随需要增加。
该类在处理一组布尔值的时候非常有用,你只需要给每个值赋值一"位",然后对位进行适当的设置或清除,就可以对布尔值进行操作了。
BitSet定义了两个构造方法
1、创建一个默认的对象:

BitSet()

2、允许用户指定初始大小。所有位初始化为0

BitSet(int size)

注:数组元素并不是只有0和1。

向量Vector类

向量(Vector)类和数组一样,Vector对象的元素可通过索引访问。
Vector 类实现了一个动态数组。和 ArrayList 很相似,但是两者是不同的:
1、Vector 是同步访问的。
2、Vector 包含了许多传统的方法,这些方法不属于集合框架。

构造方法
1、创建一个默认的向量,默认大小为 10:

Vector()

2、创建指定大小的向量。

Vector(int size)

3、创建指定大小的向量,并且增量用 incr 指定。增量表示向量每次增加的元素数目。

Vector(int size,int incr)

4、创建一个包含集合 c 元素的向量:

Vector(Collection c)

定义方法:

方法描述
void add(int index, Object element)在此向量的指定位置插入指定的元素
boolean add(Object o)将指定元素添加到此向量的末尾。
boolean addAll(Collection c)将指定 Collection 中的所有元素添加到此向量的末尾,按照指定 collection 的迭代器所返回的顺序添加这些元素。
boolean addAll(int index, Collection c)在指定位置将指定 Collection 中的所有元素插入到此向量中
void addElement(Object obj)将指定的组件添加到此向量的末尾
int capacity()返回此向量的当前容量
void clear()从此向量中移除所有元素
Object clone()返回向量的一个副本
boolean contains(Object elem)如果此向量包含指定的元素,则返回 true
int size()返回此向量中的组件数)

等等
注:初始化后,若数组元素未赋值,此时int capacity()为指定大小或默认大小,int size()为0.

import java.util.*;
public class VectorDemo {
   public static void main(String args[]) {
      // initial size is 3, increment is 2
      Vector v = new Vector(3, 2);
      System.out.println("Initial size: " + v.size());
      System.out.println("Initial capacity: " +
      v.capacity());
      v.addElement(new Integer(1));
      v.addElement(new Integer(2));
      v.addElement(new Integer(3));
      v.addElement(new Integer(4));
      System.out.println("Capacity after four additions: " +
          v.capacity());

      v.addElement(new Double(5.45));
      System.out.println("Current capacity: " +
      v.capacity());
      v.addElement(new Double(6.08));
      v.addElement(new Integer(7));
      System.out.println("Current capacity: " +
      v.capacity());
      v.addElement(new Float(9.4));
      v.addElement(new Integer(10));
      System.out.println("Current capacity: " +
      v.capacity());
      v.addElement(new Integer(11));
      v.addElement(new Integer(12));
      System.out.println("First element: " +
         (Integer)v.firstElement());
      System.out.println("Last element: " +
         (Integer)v.lastElement());
      if(v.contains(new Integer(3)))
         System.out.println("Vector contains 3.");
      // enumerate the elements in the vector.
      Enumeration vEnum = v.elements();
      System.out.println("\nElements in vector:");
      while(vEnum.hasMoreElements())
         System.out.print(vEnum.nextElement() + " ");
      System.out.println();
   }
}

注:当执行v.addElement()时,若元素还未赋值,则将值赋给此元素,并不会添加新的元素,即v.capacity()不会发生变化。

栈Stack类

栈(Stack)实现了一个先进后出,后进先出(LIFO)的数据结构。
栈是Vector的一个子类,堆栈只定义了默认构造函数,用来创建一个空栈。

Stack()

堆栈除了包括由Vector定义的所有方法,也定义了自己的一些方法。

方法描述
boolean empty()测试堆栈是否为空
Object peek( )查看堆栈顶部的对象,但不移除
Object pop( )移除堆栈顶部的对象,并返回
Object push(Object element)把项压入堆栈顶部
int search(Object element)返回对象在堆栈中的位置,以 1 为基数

字典(Dictionary)类

字典(Dictionary) 类是一个抽象类,用来存储键/值对,没有提供特定的实现。
Dictionary定义的抽象方法如下表所示:

方法描述
Enumeration elements( )返回此 dictionary 中值的枚举
Object get(Object key)返回此 dictionary 中该键所映射到的值
boolean isEmpty( )测试此 dictionary 是否不存在从键到值的映射
Enumeration keys( )返回此 dictionary 中键的枚举
Object put(Object key, Object value)将指定 key 映射到此 dictionary 中指定 value
Object remove(Object key)从此 dictionary 中移除 key (及其相应的 value)
int size( )返回此 dictionary 中条目(不同键)的数量

Dictionary类已经过时了。在实际开发中,你可以实现Map接口来获取键/值的存储功能。

Map接口

Map接口中键和值一一映射. 可以通过键来获取值。

1、给定一个键和一个值,你可以将该值存储在一个Map对象. 之后,你可以通过键来访问对应的值。

2、当访问的值不存在的时候,方法就会抛出一个NoSuchElementException异常.

3、当对象的类型和Map里元素类型不兼容的时候,就会抛出一个 ClassCastException异常。

4、当在不允许使用Null对象的Map中使用Null对象,会抛出一个NullPointerException 异常。

5、当尝试修改一个只读的Map时,会抛出一个UnsupportedOperationException异常。
方法描述
void clear( )返回此 dictionary 中值的枚举
boolean containsKey(Object k)如果此映射包含指定键的映射关系,则返回 true
boolean containsValue(Object v)如果此映射将一个或多个键映射到指定值,则返回 true
Set entrySet( )返回此映射中包含的映射关系的 Set 视图
boolean equals(Object obj)比较指定的对象与此映射是否相等
Object get(Object k)返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null
int hashCode( )返回此映射的哈希码值
boolean isEmpty( )如果此映射未包含键-值映射关系,则返回 true
Set keySet( )返回此映射中包含的键的 Set 视图
Object put(Object k, Object v)将指定的值与此映射中的指定键关联(可选操作)
void putAll(Map m)从指定映射中将所有映射关系复制到此映射中(可选操作)
Object remove(Object k)如果存在一个键的映射关系,则将其从此映射中移除(可选操作)
int size( )返回此映射中的键-值映射关系数
Collection values( )返回此映射中包含的值的 Collection 视图

map.entrySet()keySet()比较:

map.entrySet()keySet()values()
遍历hashMap将 key - value 全部取出来,性能较差根据取出的 key 值去查询对应的 value 值,若key值简单,则效率高;随着key复杂度高,entrySet更有优势只遍历 value
遍历TreeMap遍历 key-value 时候务必使用 entrySet(),性能更高只遍历 key 的时候使用 keySet(), 在只遍历 value 的是使用 values() 方法只遍历 value

哈希表(Hashtable)类

Hashtable类提供了一种在用户定义键结构的基础上来组织数据的手段。

HashMapHashtable
不支持同步支持同步
在哈希表中存储键/值对在哈希表中存储键/值对

Hashtable实现了Map接口,因此,Hashtable现在集成到了集合框架中。

当使用一个哈希表,要指定用作键的对象,以及要链接到该键的值
然后,该键经过哈希处理后所得到的散列码被用作存储在该表中值的索引

构造方法
1、默认构造方法:Hashtable()

2、创建指定大小的哈希表:Hashtable(int size)

3、创建一个指定大小的哈希表,并且通过fillRatio指定填充比例
填充比例必须介于0.0和1.0之间,它决定了哈希表在重新调整大小之前的充满程度:Hashtable(int size,float fillRatio)

4、创建一个以M中元素为初始化元素的哈希表。哈希表的容量被设置为M的两倍。Hashtable(Map m)

属性(Properties)类

Properties 继承于 Hashtable 类,表示一个持久的属性集属性列表中每个键及其对应值都是一个字符串
Properties 类被许多Java类使用。例如,在获取环境变量时它就作为System.getProperties()方法的返回值。

构造方法

1、没有默认值:Properties()

2、使用propDefault 作为默认值:Properties(Properties propDefault)

两种情况下,属性列表都为空

定义方法:

方法描述
String getProperty(String key[, String defaultProperty])用指定的键在此属性列表中搜索属性
void list(PrintStream streamOut)将属性列表输出到指定的输出流
void load(InputStream streamIn) throws IOException从输入流中读取属性列表(键和元素对)
Enumeration propertyNames( )按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)
Object setProperty(String key, String value)调用 Hashtable 的方法 put
void store(OutputStream streamOut, String description)以适合使用 load(InputStream)方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流

实例

import java.util.*;
 
public class PropDemo {
 
   public static void main(String args[]) {
      Properties capitals = new Properties();
      Set states;
      String str;
      
      capitals.put("Illinois", "Springfield");
      capitals.put("Missouri", "Jefferson City");
      capitals.put("Washington", "Olympia");
      capitals.put("California", "Sacramento");
      capitals.put("Indiana", "Indianapolis");
 
      // Show all states and capitals in hashtable.
      states = capitals.keySet(); //得到键的set视图
      Iterator itr = states.iterator();   // Iterator(迭代器)是一个接口,作用是遍历容器的所有元素
      while(itr.hasNext()) {
         str = (String) itr.next();
         System.out.println("The capital of " +
            str + " is " + capitals.getProperty(str) + ".");
      }
      System.out.println();
 
      // look for state not in list -- specify default
      str = capitals.getProperty("Florida", "Not Found");
      System.out.println("The capital of Florida is "
          + str + ".");
   }
}

集合框架

设计要满足以下几个目标:

	1、该框架必须是高性能的。

	2、该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。

	3、对一个集合的扩展和适应必须是简单的。

为此,整个集合框架就围绕一组标准接口而设计。你可以直接使用这些接口的标准实现,也可以通过这些接口实现自己的集合。
在这里插入图片描述
Java 集合框架主要包括两种类型的容器,一种是集合(Collection)存储一个元素集合,另一种是图(Map)存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等。

所有的集合框架都包含如下内容:

1、集合接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象。

接口描述
Collection 接口最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素, Java不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。Collection 接口存储一组不唯一,无序的对象
List 接口使用此接口能够精确的控制每个元素插入的位置,能够通过索引来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素。List 接口存储一组不唯一,有序(插入顺序)的对象
Set具有与 Collection 完全一样的接口, 不保存重复的元素。Set 接口存储一组唯一,无序的对象
SortedSet继承于Set,存储一组唯一,有序的集合
Map存储一组键值对象,提供key(键)到value(值)的映射。
Map.Entry描述在一个Map中的一个元素(键/值对)。是一个Map的内部类。
SortedMap继承于 Map,使 Key 保持在升序排列。
Enumeration枚举(一次获得一个)对象集合中的元素。这个传统接口已被迭代器取代

Set和List的区别

SetList
存储的是**无序的,不重复(唯一)**的数据存储的是**有序的,可以重复(不唯一)**的元素
检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变检索效率高,删除和插入效率低,会引起其他元素位置改变
实现类有HashSet,TreeSet实现类有ArrayList,LinkedList,Vector

2、集合实现(类):是集合接口的具体实现。其中一些是具体类,这些类可以直接拿来使用,而另外一些是抽象类,提供了接口的部分实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。

标准集合类汇总:

描述
AbstractCollection实现了大部分的集合接口
AbstractList继承于AbstractCollection ,实现了大部分List接口
AbstractSequentialList继承于 AbstractList ,提供了对数据元素的链式访问而不是随机访问
LinkedList实现了List接口,允许有null(空)元素。主要用于创建链表数据结构,没有同步方法,如果多个线程同时访问一个List,必须自己实现访问同步,即在创建List时候构造一个同步的List, List list=Collections.synchronizedList(newLinkedList(...));查找效率低。
ArrayList实现了List的接口,实现了可变大小的数组,随机访问和遍历元素时较快。非同步。插入删除效率低
AbstractSet继承于AbstractCollection 并且实现了大部分Set接口
HashSet实现了Set接口,不允许出现重复元素,即唯一,不保证集合中元素的顺序,允许最多包含一个值为null的元素
LinkedHashSet具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现
TreeSet该类实现了Set接口,可以实现排序等功能
AbstractMap实现了大部分的Map接口
HashMap散列表,它存储的内容是键值对(key-value)映射。实现了Map接口,根据键的HashCode值存储数据,访问速度快,最多允许一条记录的键为null,不支持线程同步
TreeMap继承了AbstractMap,并且使用一颗树
WeakHashMap继承AbstractMap类,使用弱密钥的哈希表
LinkedHashMap继承于HashMap,使用元素的自然顺序对元素进行排序
IdentityHashMap继承AbstractMap类,比较文档时使用引用相等

以及上述向量Vector向量、栈Stack、字典Dictionary、哈希表(Hashtable)、属性Properties、位向量BitSet。

ArrayList与Linkedlistbijiao比较:

ArrayListLinkedList
数组链表
遍历、查找元素快遍历、查找元素慢
添加、删除元素比较慢添加、删除元素比较快

3、算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
用于集合和映射。被定义为集合类的静态方法。

在尝试比较不兼容的类型时,一些方法能够抛出 ClassCastException异常。当试图修改一个不可修改的集合时,抛出UnsupportedOperationException异常。

集合定义三个静态的变量:EMPTY_SET,EMPTY_LIST,EMPTY_MAP的。这些变量都不可改变。

集合框架体系

java集合框架位于java.util包中, 所以当使用集合框架的时候需要进行导包

迭代器Iterator

采用迭代器遍历集合框架,它是一个对象,实现了Iterator 接口或ListIterator接口。

迭代器,使你能够通过循环来得到或删除集合的元素。ListIterator 继承了Iterator,以允许双向遍历列表和修改元素。

(1) 使用方法 iterator() 要求容器返回一个 Iterator。第一次调用 Iterator 的 next() 方法时,它返回序列的第一个元素。注意:iterator() 方法是 java.lang.Iterable 接口,被 Collection 继承。

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

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

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

实例 遍历List:

import java.util.*;
 
public class Test{
 public static void main(String[] args) {
     List<String> list=new ArrayList<String>();
     list.add("Hello");
     list.add("World");
     list.add("HAHAHAHA");
     //第一种遍历方法使用 For-Each 遍历 List
     for (String str : list) {            //也可以改写 for(int i=0;i<list.size();i++) 这种形式
        System.out.println(str);
     }
 
     //第二种遍历,把链表变为数组相关的内容进行遍历
     String[] strArray=new String[list.size()];
     list.toArray(strArray);
     for(int i=0;i<strArray.length;i++) //这里也可以改写为  for(String str:strArray) 这种形式
     {
        System.out.println(strArray[i]);
     }
     
    //第三种遍历 使用迭代器进行相关遍历     
     Iterator<String> ite=list.iterator();
     while(ite.hasNext())//判断下一个元素之后有值
     {
         System.out.println(ite.next());
     }
 }
}

实例 遍历Map

import java.util.*;
 
public class Test{
     public static void main(String[] args) {
      Map<String, String> map = new HashMap<String, String>();
      map.put("1", "value1");
      map.put("2", "value2");
      map.put("3", "value3");
      
      //第一种:普遍使用,通过map.keyset,二次取值
      System.out.println("通过Map.keySet遍历key和value:");
      for (String key : map.keySet()) {
       System.out.println("key= "+ key + " and value= " + map.get(key));
      }
      
      //第二种:通过Map.entrySet使用iterator遍历key和value
      System.out.println("通过Map.entrySet使用iterator遍历key和value:");
      Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
      while (it.hasNext()) {
       Map.Entry<String, String> entry = it.next();
       System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
      }
      
      //第三种:推荐,尤其是容量大时,通过Map.entrySet遍历key和value
      System.out.println("通过Map.entrySet遍历key和value");
      for (Map.Entry<String, String> entry : map.entrySet()) {
       System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
      }
    
      //第四种
      System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
      for (String v : map.values()) {
       System.out.println("value= " + v);
      }
     }
}

比较器 Comparator

TreeSet和TreeMap的按照排序顺序来存储元素. 然而,这是通过比较器来精确定义按照什么样的排序顺序。
这个接口可以让我们以不同的方式来排序一个集合。

Java 的快速失败和安全失败

一、快速失败(fail—fast)

在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出 Concurrent Modification Exception。

原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变 modCount 的值。每当迭代器使用 hashNext()/next() 遍历下一个元素之前,都会检测 modCount 变量是否为 expectedmodCount 值,是的话就返回遍历;否则抛出异常,终止遍历。

注意:异常的抛出条件是检测到 modCount != expectedmodCount 。如果集合发生变化时修改 modCount 值刚好又设置为了 expectedmodCount 值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的 bug。

场景:java.util 包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。

总结:在单线程的遍历过程中,如果要进行 remove 操作,可以调用迭代器的 remove 方法而不是集合类的 remove 方法。

二、安全失败(fail—safe)

1、采用安全失败机制的集合容器,使用 CopyOnWriterArrayList 代替 ArrayList,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,待完成后,才将指向旧数组的引用指向新数组,

缺点:迭代器并不能访问到修改后的内容,只能保证数据的最终一致性,不能保证数据的实时一致性

2、使用ConcurrentHashMap代替HashMap,采用了锁机制,是线程安全的。当 iterator 被创建后集合再发生改变就不再是抛出 ConcurrentModificationException,在改变时new新的数据从而不影响原有的数据 ,iterator 完成后再将头指针替换为新的数据 ,这样 iterator 线程可以使用原来老的数据,而写线程也可以并发的完成改变。即迭代不会发生 fail-fast,但不保证获取的是最新的数据

场景:Java并发包java.util.concurrent 下的容器都是安全失败,可以在多线程下并发使用,并发修改。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值