JAVA(四)类集/枚举
成鹏致远 | lcw.cnblog.com |2014-02-04
JAVA类集
1.认识类集
- 类集的作用
- 类集实际上就是一个动态的对象数组,与一般的对象数组不同,类集中的对象内容可以任意扩充
- 类集的特征
- 这种框架是高性能的
- 框架必须允许不同类型的类集以相同的方式和调度互操作方式工作
- 类集必须是容易扩展和修改的
- 对象数组中包含一组对象,但是对象数组使用的时候存在一个长度的限制,那么类集是专门解决这种限制的,使用类集可以方便的向数组中增加任意多个数据
- 对象数组的操作中基本上都要保证对象类型的一致性,对于类集而言本身其内部的元素也应该保持一致,不管是何种类型的数据,所有的操作方式都应该是一样的
- 类集框架的主要接口
- 以上的接口必须全部掌握,并且掌握各个接口的主要特点
- 所有的类集操作都存放在 java.util包中
- Collection接口使用注意
- 在一般的开发中,往往很少去直接使用 Collection接口进行开发,而基本上都是使用其子接口
- 子接口主要有:List、Set、Queue、SortedSet
- 使用子接口,可以更加清楚的表示出操作的类型(比如是否允许重复)
- List接口:可以存放重复的内容
- Set接口:不能存放重复的内容,所有的重复内容是靠 hashCode()和 equals()两个方法区分的
- Queue:队列接口
- SortedSet接口:可以对集合中的数据进行排序
- 小结
- 掌握类集就是一个动态的对象数组
- 主要的操作接口
2.List接口
- List接口中可以存放任意的数据,而且在 List接口中内容是允许重复的
- List接口的常用子类:ArrayList
- ArrayList是 List的子类,可以直接通过对象的多态性,为 List接口实例化
- 要想使用接口,则肯定要使用对象的多态性进行实例化的操作,那么对于 List接口本身也是一样的
- ArrayList中可以增加一个数据,也可以增加一组数据
- List中存在两种删除:根据对象内容、根据对象的编号
- 集合中的内容可以添加,可以删除,那么实际上最重要的就是输出
- 在 List接口中提供了 get()方法,利用此方法就可以完成输出,此输出文坛是 List接口所独有的,而其它接口是没有的,尤其是 Collection中是没有根据索引取出内容的操作
- 通过循环完成输出,循环的次数由 size()方法取得
- 集合中还有以下的操作
- 判断集合是否为空:boolean isEmpty()
- 截取部分集合:List<E> subList(int fromIndex, int toIndex),List接口扩充
- 查找指定对象是否存在:int indexOf(Object o),如果查找则返回位置,否则返回 -1
- 查找是否存在:boolean contains(Object o)
- 挽救的子类:Vector
- Vector算是一个元老级的类,在 JDK1.0的时候就存在此类,但到了 JDK1.2之后重点强调集合框架的概念,所以先后定义了很多新接口(如:List等),但是考虑到一大部分的人已经习惯了使用 Vector类,所以就让 Vector类多实现了一个 List接口,这才将其保留下来
- 但是因为其是 List子类,所以 Vector类的使用与之前的并没有太大的区别
- ArrayList与 Vector的区别
- 小结
- 掌握了以上的的操作方法,实际上 List接口的作用就明白了,而且之后的全部 操作中也基本上都是以这些方法为操作的标准,只是各个的特性不一样,例如:List中允许有重复的元素
- ArrayList和 Vector的区别
3.LinkedList类
- LinkedList表示的是一个链表的操作类,此类定义如下:public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>,Queue<E>,Cloneable,Serializable
- Queue接口是 Collection的子接口
- LinkedList本身大量的扩充了 Queue接口和 List接口的操作,所以,在使用时最好直接使用 LinkedList类完成操作
- 常用操作
- 为链表的开头和结尾增加数据
- 对于链表也可以找到其表头,可以删除表头,也可以不删除
- 此类实现了 Queue接口,可以按照队列的方式进行 FIFO的操作
- 小结
- 实际上此集合中增加元素的操作都是一样的,因为都是 Collection的子类
- 各个类有各个类自己的单独的实现,只需要单独使用即可
4.Set接口
- Set接口也是 Collection接口的子接口,但是与 Collection或 List接口不同的是,Set接口中不能加入重复的元素
- Set接口的定义:public interface Set<E> extends Collection<E>
- Set接口的主要方法与 Collection是一致的
- Set接口的实例无法像 List接口那样进行双向输出
- Set接口的常用子类
- 散列在这:HashSet
- 有序存放:TreeSet
- Collection就不能进行双向输出,因为没有提供 get()方法,但是 Set接口与 Collection接口的定义一致,所以其本身也不能双向输出
- HashSet
- 使用散列的方式存放内容,本身没有顺序
- 是无序排列的,而 List接口的内容插入的顺序就是其保存的顺序
- 如果希望所有的内容可以自动进行排序的操作,则可以使用 Set中的第二个子类:TreeSet
- TreeSet子类是可以排序的
- 小结
- Set接口的基本作用
- 两个子类的区别
- HashSet:散列存放
- TreeSet:有序存放
5.排序及重复元素说明
- TreeSet类的内容是可以排序的
- Comparable主要是进行排序的接口,一个对象数组要想排序,则依靠 Comparable接口完成,那么对于 TreeSet也一样,如果要想使用 TreeSet进行排序,则对象所在的类也必须实现 Comparable接口
- String类既然可以使用 TreeSet排序,则 String类中肯定已经实现了 Comparable接口
- 如果要想取消重复元素,则需要 Object类中的两个方法帮助
- hashCode():表示一个唯一的编码,一般通过计算表示
- equals():进行对象的比较操作
- 如果要想使用 Set,则就必须注意以上的两个问题
- 小结
- 一个好的类应该覆写 Object类中的 equals()、haskCode()、toString()三个方法,实际上在 String中已经全部覆写完成了
- Set接口依靠 hashCode()和 equals()完成重复元素的判断,关于这一点在日后的 Map接口中也有体现
- TreeSet依靠 Comparable接口完成排序的操作
6.SortedSet接口
- TreeSet类,是可以排序的操作类,TreeSet实际上也是 SortedSet接口的一个子类,所以此接口的所有类都是可以排序的
- 小结
- 只要是以 Sorted开头的接口基本上都是表示可以排序的接口
7.Iterator接口
- 在集合的操作中支持以下几种方式
- Iterator
- ListIterator
- foreach输出
- Enumeration
- Iterator接口简介
- 集合输出的标准操作:在使用集合输出的时候必须形成以下的一个思路:只要是碰到了集合输出的操作,就一定使用 Iterator接口,因为这是最标准的做法
- Iterator接口的操作原理
- Iterator是专门的迭代输出接口,所谓的迭代输出就是将元素一个个进行判断,判断其是否有内容,如果有内容则把内容取出
- 对于 Iterator而言,因为其本身是一个接口,所以要想实例化则必须依靠 Collection接口完成
- 在 Iterator接口中提供了 remove()方法,此方法的功能是删除当前的对象
- 在实际中 Iterator是很少调用删除操作的,因为其本身的功能就是输出内容
- 对于删除操作也有以下一个注意点
- List接口本身存在删除方法:remove
- 如果在使用迭代输出的过程中使用了 List中的 remove()执行删除操作,则会出现问题
- 所以,在使用 Iterator输出时,不要使用集合类中的 remove()方法,而只能使用 Iterator接口中的 remove方法
- 小结
- Iterator接口的功能是从前向后输出,属于单身的输出
- Iterator的主要功能就是完成迭代输出操作的
- 在使用 Iterator的时候最好不要删除数据
8.ListIterator接口
- Iterator接口的主要功能是由前向后单身输出,而此时如果想实现由后向前或由前向后的双向输出,则就必须使用 Iterator的子接口:ListIterator
- ListIterator接口定义:public interface ListIterator<E> extends Iterator<E>
- 虽然此接口可以进行双向输出,但是遗憾的是 Collection接口中并没有定义可以为此类实例化的操作,只有 List接口中才存在了 ListIterator接口的实例化操作
- 【注意】在使用此操作的时候一定要注意:一定要先进行由前向后的输出,之后才能进行由后向前的输出
- 使用 ListIterator还可以进行增加及替换元素
- add()
- set()
- 小结
- 如果要想使用 ListIterator则只能依靠 List接口完成
- 如果要进行由后向前的输出,则只能先进行由前向后的输出
- 对于此接口中的增加及修改操作了解即可
9.foreach及 Enumeration接口
- 在 JDK1.5之后增加了许多新的功能,其中 foreach可以输出数组,实际上 foreach语法也同样支持集合的输出操作
- 实际上 Iterator属于一个新的输出接口,在最早 java刚出来的时候如果要想输出,使用 Enumeration接口完成输出
- 【注意】在使用 Enumeration输出的时候一般都是直接操作 Vector类完成的
- 小结
- 在所有的输出操作中,以 Iterator接口为最标准的输出操作,这一点始终要记住
- 在部分旧的操作中 Enumeration依然存在
10.Map接口
- Collection的操作每次保存的对象都是一个对象,但是在 Map中保存的是一对对象,对象的形式是以:key ->value的形式保存的
- Map与 Map.Entry
- Map接口的常用子类
- HashMap:无序存放的,是新的操作类,key不允许重复
- Hashtable:无序存放的,是旧的操作类,key不允许重复
- TreeMap:可以排序的 Map集合,按集合中的 Key排序,key不允许重复
- WeakHashMap:弱引用的 Map集合,当集合中的某些内容不再使用时,可以清除掉无用的数据,可以使用 gc进行回收
- IdentityHashMap:key可以重复的 Map集合
- 在 map中也可以使用 containsXxx()方法判断指定的 key或者 value是否存在
- 返回全部的 key:Set<K> keySet()
- 返回全部的 value:Collection<V> values()
- 在 Map中也存在一个 Hashtable子类,实际上这个子类的推出时间与 Vector是一样的,都属于旧的类
- HashMap与 Hashtable的区别
- 在 Map中还存在一个 TreeMap的子类,此类也属于排序类,按 key排序
- 使用 TreeMap可以方便的完成排序的操作
- 如果自定义的类要想做为 key的话,则肯定要实现 Comparable接口,指定比较的规则
- 弱引用类:WeakHashMap
- 之前的 Map子类中的数据都是使用强引用保存的,即:里面的内容不管是否使用都始终在集合中保留,如果希望集合可以自动清理暂不用的数据就可以使用 WeakHashMap类
- 对象的引用强度说明
- 从 JDK1.2版本开始,Java把对象的引用分为四种级别,从而使程式能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用
- 强引用:当内存不足时,JVM宁可出现 OutOfMemeryError错误而使程序停止,也不会回收此对象来释放空间
- 软引用:当内存不足时,会回收这些对象的内存,用来实现内存敏感的调整缓存
- 弱引用:无论内存是否紧张,被垃圾回收器发现立即回收
- 虚引用:和没有任何引用一样
- 小结
- 介绍了 Map的特点及基本操作
- Map与 Map.Entry的关系
- Map的子类:HashMap、Hashtable、TreeMap、WeakHashMap
- 主要功能就是查找,根据 key找到 value
11.Map接口使用注意事项
- Map接口输出:对于 Map接口来说,其本身是不能直接使用迭代的(例如:Iterator、foreach)进行输出的,因为 Map中的每个位置存放的是一对值(key ->value)而 Iterator中每次只能找到一个值,所以,如果此时非要使用迭代进行输出的话,则必须按照以下的步骤完成(以 Iterator输出为例)
- 将 Map的实例通过 entrySet()方法变为 Set接口对象
- 通过 Set接口实例为 Iterator实例化
- 通过 Iterator迭代输出,每个内容都是 Map.Entry的对象
- 通过 Map.Entry进行 key ->value的分离
- Map接口一般只作为查找使用,输出的操作属于少数
- 在 JDK1.5之后也可以使用 foreach完成,而且更简单
- 两种输出形式最终实际上还是以 Collection的形式输出,只是以 Map.Entry作为内容的操作类型
- 在 Map中,可以使用任意的类型作为 key和 value,那么使用非系统类也可以
- 直接使用非系统类作为 key
- 如果要使用非系统类作为 Map的 key,则此类必须覆写 Object类中的以下两个方法
- hashCode()
- equals
- 作为 key,或者更准确的说是作为对象的时候,实际上是依靠 hashCode()和 equals()来判断两个匿名对象是否相等,这一点由系统内部自动完成
- 小结
- Map可以使用迭代输出
- map ->entrySet ->Set ->Iterator ->Map.Entry ->key和 value
- 如果使用非系统类作为 key,则一定要保存覆写 equals和 hashCode()方法,否则无效
14.IdentityHashMap类
- 在正常的 Map操作中,key本身是不能够重复的
- 使用 HashMap操作的时候,key内容是不能重复的,如果现在希望 key的内容可以重复(指的重复是指两个对象的地址不一样)则要使用 IdentityHashMap类
- 就算是两个对象的内容相等,是只要地址不等,那么就可以加入进行,key是可以重复的
15.SortedMap接口
- SortedSet,是 TreeSet的实现接口,那么此接口可以进行排序的操作
- SortedMap也是排序的操作,之前学习过 TreeMap类,那么此类是可以排序的
- 小结
- 认识 Map接口的子接口 SortedMap接口的基本概念
- 在此接口有很多的操作方法
- 在实际中还是以 Map接口为操作的标准
14.集合工具类:Collections
- 【面试题】Collections和 Collection的关系
- Collections类与 Collection没有直接的关系,但是与集合中的各个接口都有操作的方法支持
- 操作方法
- 空集合操作:emptyList()/emptySet()
- 添加内容:addAll(Collection<? super T> c,T... elements),使用可变参数,所以,可以任意输入各种类型的数据
- 二分检索:binarySearch()
- 替换内容:replaceAll()
- 排序操作:sort(),如果要进行排序的话,则肯定对象所在的类必须实现 Comparable接口
- 交换内容:swap()
- 小结
- 在类集中为了方便集合的操作提供了 Collections类,此类与 Collection接口没有直接的继承或实现关系,只是对所有的接口有所支持而已
- 开发中是否使用此类没有明确的规定,按照个人的喜好执行即可
15.Stack类
- 栈是数据结构中比较常见的一种形式,栈是采用典型的先进后出的操作方式完成的
- 每一个栈都包含一个栈顶,每次出栈是将栈顶的数据取出
- 在 Java中使用 Stack类进行栈的操作,Stack类是 Vector的子类,Stack类的定义如下:public class Stack<E> extends Vector<E>
- 如果栈中已经没有内容了,则无法继续出栈
16.属性类:Properties
- 属性是在程序中经常出现的一种形式
- 在类集中提供了一个专门的 Properties类,以完成属性的操作:public class Properties extends Hashtable<Object, Object>
- Properties是 Hashtable的子类,则也是 Map的子类,可以使用 Map的全部操作,但是一般情况下属性类是单独使用的
- 设置和取得属性:public Object setProperty(String key, String value)
- 得到属性:public String getProperty(String key) / public String getProperty(String key, String defaultValue)
- 属性也可以保存到文件之中:public void store(OutputStream out, String comments) throws IOException
- 从文件之中读取:public void load(InputStream inStream) throws IOException
- 同样也可以将文件保存在 XML文件中,从 XML文件中读取
- 小结
- 如果要进一步了解属性操作,则可以继续学习反射机制部分,发解属性类的应用
- 属性中的类型肯定都是字符串,因为操作最方便
- 属性可以向普通文件或 XML文件中保存或读取,按照指定格式可以向文件中任意扩充属性
枚举
1.枚举的作用
- 在 JDK1.5之前,JAVA可以有两种方式定义新类型:类和接口
- 对于大部分面向对象编程来说,这两种方法看起来似乎足够我,但是在一些特殊情况下,这些方法就不适合了
- 例如:想定义一个 Color类,它只能有 Red、Green、Blue三种值,其它的任何值都是非法的,那么 JDK1.5之前虽然可以构造这样的代码,但是要做很多的工作,也有可能带来各种不安全的问题,而在 JDK1.5之后引入的枚举类型(Enum)就能避免这些问题
- 所谓的枚举就是:规定好了指定的取值范围,所有的内容只能从指定的范围中取得
- 因为枚举已经指定好了范围,所以可以使用 foreach进行全部的输出,使用“枚举.values()”的形式取得全部的枚举内容
- 枚举还可以直接将内容在 Switch语句上使用
- 小结
- 使用枚举可以限制取值的范围
- 使用 enum关键字可以定义枚举
2.Enum类
- 使用 enum关键字可以定义一个枚举,实际上此关键字表示的是 java.lang.Enum类型,即:使用 enum声明的枚举类型,就相当于定义一个类,而此类则默认继承 java.lang.Enum类
- public abstract class Enum<E extends Enum<E>> extends Object implements Comparable<E>, Serializable
- 此类定义的时候使用了泛型机制,而且实现了 Comparable接口以及 Serializable接口,证明此种类型是可以比较的,可以被序列化的
- 构造方法:protected Enum(String name, int ordinal) 构造方法中接收两个参数:一个表示枚举的名字,另外一个表示枚举的序号
- 可以在枚举类中定义属性及自己的构造方法,但是一旦定义有参构造之后,在声明枚举对象的时候就必须明确的调用构造方法,并传递参数
- 对于枚举.class是 java反射机制中的内容
- 在枚举中实际已经实现好了 Comparable接口,所以枚举中的内容是可以排序的
- 小结
- Enum类的作用
- enum关键字与 Enum类的关系
3.类集对 Enum的支持
- EnumSet是 Set接口的子类,所以里面的内容是无法重复的
- 在使用 EnumSet的时候是不能使用关键字 new为其进行实例化的,所以在此类中提供了很多的静态方法
- EnumSet操作(基本是静态方法)
- 将全部的集合设置到 EnumSet集合中:EnumSet.allOf()
- 只设置一个内容到集合:EnumSet.of()
- 创建时放入指定枚举类型的集合:EnumSet.noneOf()
- 创建不包含指定元素的集合:EnumSet.complementOf()
- 拷贝一个集合的内容:EnumSet.copyOf()
- 小结
- EnumMap和 EnumSet
- EnumMap是符合 Map的操作形式的
- EnumSet基本上就是都使用静态方法完成
- 在操作中大量的使用了枚举.class,这个属于 java反射机制
4.枚举的其它应用
- 枚举类型可以跟普通的类一样实现一个接口,但是实现接口的时候要求枚举的每个对象都必须单独覆写好接口中的抽象方法
- 还可以直接在枚举中定义抽象方法,但是要求枚举中的每个对象都分别实现抽象方法
- 枚举的最大作用在于限定取值范围