概述
-------android培训、java培训、期待与您交流! ----------
1. Java集合
Java集合类也成Java容器类,是Java中实用的工具,实现了一些常用的数据结构和方法,方便开发者调用。集合类和数组不一样,数组中可以存放基本类型的变量也可以存放对象,容器类中只能存放对象(实际上是对象的引用)。Java的集合类主要由两个接口派生而出:Collection和Map,Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类,如下图是Collection接口的继承树:
如图所示:Set和List接口是Collection的两个子接口,它们分别代表了无序集合和有序集合;Queue是Java提供的队列实现,有点类似于List。
下图显示的是Map接口的子接口及其及继承树:
所有的Map实现类用于保存具有映射关系的数据,上图显示了Map的众多实现类,它们的功能各有不同,但都是存放的键值对。
2.Set集合
Set集合类似于一个罐子,放进去的元素是无序的。Set集合类似于Collection但Set集合不能存放相同的元素。
Set判断两个元素是否相同不是通过 == 而是 equals() 方法。
1) HashSet类
Hash是Set的典型实现类,也是Set中使用最多的类。HashSet使用Hash算法存放元素,有很好的存取和查找性能。
特点:
①不能保证元素的排列顺序。
②不同步。当两个线程同时访问一个HashSet时,假设他们同时修改HashSet元素,必须通过代码保证同步性。
③集合元素可以是null。
判断元素相同标准:
HashSet通过equals()以及hashCode()两个方法判断两个元素是否相同。如果两个元素euqals()比较返回true但hashCode不同,HashCode同样认为这是两个不同的元素。
示例:
class TestA {
public boolean equals(Object obj){
return true;
}
}
//类B的hashCode()方法总是返回1,但没有重写其equals()方法
class TestB {
public int hashCode(){
return 1;
}
}
//类C的hashCode()方法总是返回2,且有重写其equals()方法
class TestC {
public int hashCode(){
return 2;
}
public boolean equals(Object obj) {
return true;
}
}
public class HashSetTest {
public static void main(String[] args) {
HashSet hs = new HashSet();
//分别向hs集合中添加两个TestA对象,两个TestB对象,两个TestC对象
hs.add(new TestA());
<span style="font-family: Arial, Helvetica, sans-serif;">hs</span><span style="font-family: Arial, Helvetica, sans-serif;">.add(new TestA()); //返回true,添加成功。两个对象的equals()虽然为true,但hashCode不同,HashSet视为不同对象</span>
<span style="font-family: Arial, Helvetica, sans-serif;">hs</span>.add(new TestB());
hs.add(new TestB()); <span style="font-family: Arial, Helvetica, sans-serif;">//返回true,添加成功。对象的hashCode恒定返回2,所以相等,但两个对象指向不同。使用Object类的equals()方法进行比较时返回false, ,HashSet视为不同对象</span>
hs.add(new TestC());
hs.add(new TestC()); //添加失败,两个对象的equals()返回true,且hashCode返回2相等,所以无法添加元素,返回false
System.out.println(hs);
}
}
HashSet中euqlas()返回ture并且hashCode()相等才判断为同一元素,如果euqals()为true但hashCode()不同,则存放元素时按hash值存放。如果hashCode相等,但equals为false,则会在原来hashcode位置使用链式存放,会导致性能下降。
2) LinkedHashSet
使用链表维护容器内元素的顺序,输出时与添加元素的顺序一致。其他特性与HashSet一致。
示例:
public class LinkedHashSetTest {
public static void main(String[] args) {
LinkedHashSet lhs = new LinkedHashSet();
lhs.add("天空飘来5个字");
lhs.add("那都不是事");
System.out.println(lhs);
//删除 天空飘来5个字
lhs.remove("天空飘来5个字");
//重新添加 天空飘来5个字
lhs.add("天空飘来5个字");
System.out.println(lhs);
}
}
3)TreeSet
TreeSet是SortedSet接口的实现类。TreeSet中的元素总是有序的。
TreeSet采用红黑树存放元素。当一个元素被添加到TreeSet中时,系统会调用对象的compareTo(Object obj)方法与容器的其他元素比较确定元素的存放位置。所以添加到TreeSet的元素必须实现Comparable接口,否则在添加时会抛出ClassCastException异常。如以下代码所示:
class Tmp {
}
public class TreeSetExceptionTest {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
//向TreeSet集合中添加两个Tmp对象
ts.add(new Tmp()); //可以正常添加,因为容器没有元素,不用进行比较
//由于Tmp类未实现Comparable接口所以,当向TreeSet中插入第2个元素时,系统会抛出异常
ts.add(new Tmp());
}
}
对于TreeSet而言,判断两个元素是否相等唯一的条件是compareTo()方法返回0;
总结:HashSet和TreeSet是Set的两个典型实现。一般情况下HashSet的性能好于TreeSet,因为TreeSet需要维护红黑树来保持集合元素的次序。HashSet的子类LinkedHashSet的性能没有HashSet高,同样是要维护一个链表。但应为有链表所以LinkedHashSet的遍历速度优于HashSet,EnumSet的性能最好。
3. List集合
List集合代表一个有序的,可重复的集合,集合的中每个元素都有对应的索引,可通过该索引随机访问集合中的元素。对应的数据结构为线性表。1) List接口
List接口是Collection接口的子接口,扩展了一些线性表特有的方法:
示例:
public class ListTest {
public static void main(String[] args) {
List names = new ArrayList();
//向names集合中添加三个元素
names.add(new String(""));
names.add(new String("张三"));
names.add(new String("李四"));
System.out.println(names);
//将新字符串对象插入在第二个位置
names.add(1 , new String("王五"));
for (int i = 0 ; i < names.size() ; i++ ) {
System.out.println(names.get(i));
}
//删除第三个元素
names.remove(2);
System.out.println(names);
//判断指定元素在List集合中位置:输出1,表明位于第二位
System.out.println(names.indexOf(new String("王五")));
//将第二个元素替换成新的字符串对象
names.set(1, new String("王五"));
System.out.println(names);
//将names集合的第二个元素(包括)
//到第三个元素(不包括)截取成子集合
System.out.println(names.subList(1 , 2));
}
}
List判断元素相等是通过equals()方法。List接口中的indexOf()、remove()等需要差早和比较元素的方法都是通过equals()方法确定元素是否相等,而不是通过判断元素的引用对象是否是同一对象。
示例:
class A {
public boolean equals(Object obj) {
return true;
}
}
public class ListTest2 {
public static void main(String[] args) {
List names = new ArrayList();
names.add(new String("张三"));
names.add(new String("李四"));
names.add(new String("王五"));
System.out.println(names);
//删除集合中A对象,将导致第一个元素被删除
names.remove(new A());
System.out.println(names);
//删除集合中A对象,再次删除集合中第一个元素
names.remove(new A());
System.out.println(names);
}
}
2) ArrayList和Vertor实现类
ArrayList和Vertor是List的两个典型实现类。两者内部使用数组存放元素,所以其内部有一个Object[]的动态数组。
ArrayList和Vertor使用initialCapacity设置数组的长度,当元素数量超出数组的长度是,数组容量会自动增加。用户在使用两个集合类是无需关心initialCapacity的大小,系统会自动以及增长。当需要一次性添加大量元素时,可以将initialCapacity属性设置为一个较大的数字已减少系统扩充数组容量的次数,提升性能。
示例:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>(20); //设置初始化容量为20,如不设置默认容量为10
list.ensureCapacity(500); //使用ensureCapacity()方法重行设置数组容量
list.trimToSize(); //将ArrayList长度缩减到当前数组当前元素的数量,可以使ArrayList占用的空间最小化
}
Vertor与ArrayList不同的是前者是线程安全的,当性能较ArrayList低,一般情况下不推荐使用。
4. Queue集合
Queue用于模拟队列这种数据结构,队列是指FIFO的容器。队列的头部保存在队列中存放时间最长的元素,队列的尾部保存在队列中存放时间最短的元素。新元素插入在队列的尾部,访问元素操作会返回队列头部的元素。Queue定义了如下几个方法:
- vod add(Object e)将指定元素插入队尾
- Object elenent() 获取队列头部的元素,但不删除该元素
- boolean offer(Object e)将指定元素加入此队列的尾部,性能较好
- Object peek()获取队列头部的元素,但不删除该元素。
- Object poll()获取队列头部的元素,并删除该元素。
这是一个标准额队列实现类,PriorityQueue保存队列元素的顺序并不是按照加入的顺序,而是按队列元素的大小进行排序。当调用peek()和poll()方法是,是去除队列中最小的元素。下面是该类的用法:
public class PriorityQueueTest {
public static void main(String[] args) {
PriorityQueue pq = new PriorityQueue();
//下面代码依次向pq中加入四个元素
pq.offer(6);
pq.offer(-3);
pq.offer(9);
pq.offer(0);
//输出pq队列,并不是按元素的加入顺序排列,
//而是按元素的大小顺序排列,输出[-3, 0, 9, 6]
System.out.println(pq);
//访问队列第一个元素,其实就是队列中最小的元素:-3
System.out.println(pq.poll());
}
}
注意:PriorityQueue不允许插入null对象
2)Deque和ArrayDeque实现类
Deque是Queue的子接口,它代表一个双端队列,Deque不仅可以当作队列使用还可以当作栈使用。Deque提供了一个典型的实现类:ArrayDeque,从该名称来看,这是一个基于数组实现的双端队列。下面示例将ArrayDeque当作堆栈来使用:
public class ArrayDequeTest {
public static void main(String[] args) {
ArrayDeque stack = new ArrayDeque();
//依次将三个元素push入"栈"
stack.push("大学英语");
stack.push("高等数学");
stack.push("大学物理");
//输出:[大学英语, 高等数学 , 大学物理]
System.out.println(stack);
//访问第一个元素,但并不将其pop出"栈",输出:大学物理
System.out.println(stack.peek());
//依然输出:[大学英语, 高等数学 , 大学物理]
System.out.println(stack);
//pop出第一个元素,输出:大学物理
System.out.println(stack.pop());
//输出:[大学英语, 高等数学]
System.out.println(stack);
}
}
5. HashMap和Hashtable集合
它们都是Map接口的实现类,它们之间的区别如下:Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的实现,所以HashMap比Hashtable的性能高一点;但如果有多了线程访问同一个Map对象时,使用Hashtable实现类更好。
Hashtable不允许使用Null作为key和value,但HashMap可以使用null作为key或者value。
下面演示null作为HashMap的key和value的情况:
public class NullInHashMap {
public static void main(String[] args) {
HashMap hm = new HashMap();
//试图将两个key为null的key-value对放入HashMap中
hm.put(null , null);
hm.put(null , null); //①
//将一个value为null的key-value对放入HashMap中
hm.put("a" , null); //②
//输出Map对象
System.out.println(hm);
}
}
HashMap判断两个key相等的标准是:两个key通过equals()比较返回true,两个key的hashCode值相等。
HashMap判断两个value相等的标准是:两个value通过equals()表叫返回true。下面程序演示了hashtable判断两个key相等和两个value相等的标准。
class A {
int count;
public A(int count) {
this.count = count;
}
//根据count的值来判断两个对象是否相等。
public boolean equals(Object obj) {
if (obj == this)
return true;
if (obj!=null &&
obj.getClass()==A.class) {
A a = (A)obj;
return this.count == a.count;
}
return false;
}
//根据count来计算hashCode值。
public int hashCode() {
return this.count;
}
}
class B {
//重写equals()方法,B对象与任何对象通过equals()方法比较都相等
public boolean equals(Object obj) {
return true;
}
}
public class HashtableTest {
public static void main(String[] args) {
Hashtable ht = new Hashtable();
ht.put(new A(60000) , "大学英语");
ht.put(new A(87563) , "高等数学");
ht.put(new A(1232) , new B());
System.out.println(ht);
//只要两个对象通过equals比较返回true,
//Hashtable就认为它们是相等的value。
//由于Hashtable中有一个B对象,
//它与任何对象通过equals比较都相等,所以下面输出true。
System.out.println(ht.containsValue("测试字符串")); //①
//只要两个A对象的count相等,它们通过equals比较返回true,且hashCode相等
//Hashtable即认为它们是相同的key,所以下面输出true。
System.out.println(ht.containsKey(new A(87563))); //②
//下面语句可以删除最后一个key-value对
ht.remove(new A(1232)); //③
//通过返回Hashtable的所有key组成的Set集合,
//从而遍历Hashtable每个key-value对
for (Object key : ht.keySet()) {
System.out.print(key + "---->");
System.out.print(ht.get(key) + "n");
}
}
}
最后
以上就是大气烤鸡为你收集整理的【黑马程序员】Java集合类的全部内容,希望文章能够帮你解决【黑马程序员】Java集合类所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复