关于JDK中的集合总结(二)

1.2版本的JDK才出现的java集合框架。

下面介绍说一下Vector的一些特点。

 1 import java.util.Enumeration;
 2 import java.util.Iterator;
 3 import java.util.Vector;
 4 public class VectorDemo {
 5     public static void main(String[] args) {
 6 
 7         Vector v = new Vector();
 8         v.addElement("abc1");
 9         v.addElement("abc2");
10         v.addElement("abc3");
11         v.addElement("abc4");
12         
13         Enumeration en = v.elements();
14         while(en.hasMoreElements()){
15             System.out.println("nextelment:"+en.nextElement());
16         }
17         Iterator it = v.iterator();
18         while(it.hasNext()){
19             System.out.println("next:"+it.next());
20         }
21     }
22 }

方法名上只要有Elements的都是Vector特有 的方法。

Vector中有一个elements()方法。 

Enumeration<E>

elements()
          返回此向量的组件的枚举。

接口 Enumeration<E>

注:此接口的功能与 Iterator 接口的功能是重复的。此外,Iterator 接口添加了一个可选的移除操作,并使用较短的方法名。新的实现应该优先考虑使用 Iterator 接口而不是 Enumeration 接口。

从以下版本开始:

JDK1.0

Enumeration接口也是很早就出现的,但是现在基本上不用了,在jdk2.0之前都是使用该方法进行遍历的,那时候还没有Iterator接口。但是由于其名字比较长,而郁郁而终。

例如,要输出 Vector<E> v 的所有元素,可使用以下方法: 

for (Enumeration<E> e = v.elements(); e.hasMoreElements();)
       System.out.println(e.nextElement());

上面是java API中的描述,重点是使用了for循环。

LinkedList

void

addFirst(E e)
          将指定元素插入此列表的开头。

 void

addLast(E e)
          将指定元素添加到此列表的结尾。

 E

getFirst()
          
返回此列表的第一个元素。

 E

getLast()
          
返回此列表的最后一个元素。

  

E

remove()
          获取并移除此列表的头(第一个元素)。

 E

remove(int index)
          移除此列表中指定位置处的元素。

 

LinkedList:

          addFirst();

         addLast():

 

         jdk1.6

         offerFirst();在此列表的开头插入指定的元素

         offerLast();在此列表末尾插入指定的元素。

         getFirst();.//获取但不移除,如果链表为空,抛出NoSuchElementException.

         getLast();

 

         jdk1.6

         peekFirst();//获取但不移除,如果链表为空,返回null.

         peekLast():

        

         removeFirst();//获取并移除,如果链表为空,抛出NoSuchElementException.

         removeLast();

         jdk1.6

         pollFirst();//获取并移除,如果链表为空,返回null.

         pollLast();

 

自动装箱:基本数据类型转换成引用数据类型。

自动拆箱:引用数据类型和基本数据类型做运算的时候。

ArrayList集合存储自定对象:

Person.java

 1 public class Person {
 2     private String name;
 3     private int age;
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public int getAge() {
11         return age;
12     }
13     public void setAge(int age) {
14         this.age = age;
15     }
16     public Person(String name, int age) {
17         super();
18         this.name = name;
19         this.age = age;
20     }
21 }

ArrayListTest.java

 1 import java.util.ArrayList;
 2 import java.util.Iterator;
 3 public class ArrayListTest {
 4     public static void main(String[] args) {
 5         ArrayList list = new ArrayList();
 6         
 7         list.add(new Person("lisi1",11));
 8         list.add(new Person("lisi2",12));
 9         list.add(new Person("lisi3",13));
10         list.add(new Person("lisi4",14));
11 
12         Iterator it =list.iterator();
13         while(it.hasNext()){
14             //System.out.println(((Person) it.next()).getName()+"--"+((Person) it.next()).getAge());
         //
输出:
//lisi1--12
         //lisi3—-14   出现名字和姓名交错的现象原因就是next()访问完一个对象之后接着去访问下一个对象。
15             Person p = (Person) it.next();
16             System.out.println(p.getName()+"----"+p.getAge());
17         }
18     }
19 }

  输出结果:

lisi1----11
lisi2----12
lisi3----13
lisi4----14

 

Set:元素不可以重复,是无序的。

         Set接口中的方法和Collection一致。

         |--HashSet: 内部数据结构是哈希表 ,是不同步的。

                   如何保证该集合的元素唯一性呢?

                   是通过对象的hashCode和equals方法来完成对象唯一性的。

                   如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。

                   如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。

                   如果为true,视为相同元素,不存储。如果为false,那么视为不同元素,就进行存储。

                   记住:如果元素要存储到HashSet集合中,必须覆盖hashCode方法和equals方法。

                   一般情况下,如果定义的类会产生很多对象,比如人,学生,书,通常都需要覆盖equals,hashCode方法。

                   建立对象判断是否相同的依据。

哈希算法是底层windows做的,而且针对不同的对象有不同的哈希算法运算。

java类中有的哈希算法是native用的windows底层 的,有的根据对象的不同进行了重写。

哈希表:哈希这种算法会算出很多的值,把这些值存储起来形成一个表。表中有对应关系。

哈希表中还是数组。只是哈希这种算法对数组进行了优化。

哈希算法有一种最常见的算法就是取余。

哈希表中不能有重复的元素。

哈希表是如何判断元素是否是重复的?

“ab”和”ba”产生的哈希值是一样的,取余之后都是5,但是内容不一样,哈希值对这样的情况也有对应的方法,在5角标出“挂”一个”ba”。

 

在list集合remove和contains都要判断相不相同,都是用的equals、

如果到了set集合,要删除一个元素,要依据该元素是否和该容器中的元素是否相同

hashset依据hashcode和equals。

用HashSet存储自定义对象

Person.java

 1 public class Person {
 2     private String name;
 3     private int age;
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public int getAge() {
11         return age;
12     }
13     public void setAge(int age) {
14         this.age = age;
15     }
16     public Person(String name, int age) {
17         super();
18         this.name = name;
19         this.age = age;
20     }
21 }

HashSetTest.java

 1 import java.util.HashSet;
 2 import java.util.Iterator;
 3 public class HashSetTest {
 4     public static void main(String[] args) {
 5         HashSet set = new HashSet();
 6         set.add(new Person("lisi1",11));
 7         set.add(new Person("lisi2",12));
 8         set.add(new Person("lisi3",13));
 9         set.add(new Person("lisi4",14));
10         set.add(new Person("lisi4",14));
11         Iterator it = set.iterator();
12         while(it.hasNext()){
13             Person p = (Person) it.next();
14             System.out.println(p.getName()+"---"+p.getAge());
15         }
16     }
17 }

打印的结果是:

lisi3---13

lisi4---14

lisi1---11

lisi2---12

lisi4---14

集合中存储进去了两个“lisi4 14”又是集合Set ,Set集合中不会再存储相同的元素。为什么出现这种情况。

首先这是Set存储用户自定义对象。

其次Person类继承的是Object,每new一个Person都有不同的地址值,hashcode不同,对于Set集合来说是不同的元素。

第三你自己定义的只要名字和年龄一样就是不同的对象这个规则程序现在是不知道的。需要你自己去定义,完善

修改之后的代码:

Person.java

 1 public class Person extends Object {
 2     private String name;
 3     private int age;
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public int getAge() {
11         return age;
12     }
13     public void setAge(int age) {
14         this.age = age;
15     }
16     public Person(String name, int age) {
17         super();
18         this.name = name;
19         this.age = age;
20     }
21     //hashCode()方法返回的是一个int类型的值,这里根据Person类对象的特点,返回一个由name和age属性决定的值最合适。age之后乘以的数字只要不是1,都可以。
22     @Override
23     public int hashCode() {
24         System.out.println(this+".......hashCode");
25         return name.hashCode()+age*27;
26     }
27     @Override
28     public boolean equals(Object obj) {
29         if(this == obj)
30             return true;
31         if(!(obj instanceof Person))
32             throw new ClassCastException("类型错误");
33         System.out.println(this+"....equals....."+obj);
34         Person p = (Person)obj;
35         return this.name.equals(p.name) && this.age == p.age;
36     }
37     public String toString(){
38          return name +":"+ age;
39     }
40 }

从输出的结果可以看出来,这两句if语句并没有执行,因为如果执行了就不会再执行下面的语句了,if中的语句是return结束语句。我在debug模式下inspect监察if中的语句也都是false。

第二if语句感觉到确实是有用,第一句有什么用处呢?

第一if语句的用处就在于,当判断完hashCode()方法之后hash值相同,如果内容也相同,就用if(this ==obj),这样结束equals语句中的判断。

在写上面这段代码时候,我没有重写toString方法,程序就会报错。

Exception in thread "main" java.lang.StackOverflowError

    at java.lang.Object.toString(Unknown Source)

    at java.lang.String.valueOf(Unknown Source)

    at java.lang.StringBuilder.append(Unknown Source)

    at Mypack.Person.hashCode(Person.java:26)

如果不重写此方法打印的就是对象,如果不重写toString就是打印的hashcode值,但是这里重写了hashCode方法。

 

HashSetTest.java

 1 import java.util.HashSet;
 2 import java.util.Iterator;
 3 public class HashSetTest {
 4     public static void main(String[] args) {
 5         HashSet set = new HashSet();
 6         set.add(new Person("lisi1",11));
 7         set.add(new Person("lisi2",12));
 8         set.add(new Person("lisi3",13));
 9         set.add(new Person("lisi4",14));
10         set.add(new Person("lisi4",14));
11         Iterator it = set.iterator();
12         while(it.hasNext()){
13             Person p = (Person) it.next();
14             //System.out.println(p);
15             System.out.println(p.getName()+"---"+p.getAge());
16         }
17     }
18 }

输出:

lisi1:11.......hashCode

lisi2:12.......hashCode

lisi3:13.......hashCode

lisi4:14.......hashCode

lisi4:14.......hashCode

lisi4:14....equals.....lisi4:14

lisi2---12

lisi1---11

lisi4---14

lisi3---13

从上面的输出可以看出在初始化Set集合的时候调用了hashCode()方法,在初始化第二个lishi4的时候set就对其中的元素进行了check,用到了equals方法。

System.out.println(age.hashCode());

System.out.println(name.hashCode());

当时很纳闷name作为一个类中的属性,怎么能有hashCode()方法呢hashCode()方法不是对象才所具有的吗?于是我就尝试打印age的哈希值,报这个错误:Cannot invoke hashCode() on the primitive type int。

hashCode()确实只有对象才有,但是age是个int类型的,name是String类型的,String类型是对象类型。所以name属性有hashCode()方法。

 /*

 * 定义功能去除ArrayList中的重复元素。

 */

Person.java

 1 public class Person extends Object {
 2     private String name;
 3     private int age;
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public int getAge() {
11         return age;
12     }
13     public void setAge(int age) {
14         this.age = age;
15     }
16     public Person(String name, int age) {
17         super();
18         this.name = name;
19         this.age = age;
20     }
21     public String toString(){
22         return name +":"+ age;
23     }    
24     
25     @Override
26     public boolean equals(Object obj) {
27         
28         if(this == obj)
29             return true;
30         if(!(obj instanceof Person))
31             throw new ClassCastException("类型错误");
32         Person p = (Person)obj;
33         return this.name.equals(p.name) && this.age == p.age;
34     }
35 }

ArrayList中判断元素是否存在就只重写了一个equals()方法。

用equals()方法来判断对象的属性值是否都相同。

ArrayListTest2 .java

 1 public class ArrayListTest2 {
 2     public static void main(String[] args) {
 3         ArrayList al = new ArrayList();
 4         al.add(new Person("lisi1",21));
 5         al.add(new Person("lisi2",22));
 6         al.add(new Person("lisi3",23));
 7         al.add(new Person("lisi4",24));
 8         al.add(new Person("lisi2",22));
 9         al.add(new Person("lisi3",23));
10         
11         System.out.println(al);
12         al = getSingleElement(al);
13         
14         System.out.println(al.remove(new Person("lisi2",22))); //返回值是true
      //
虽然这个地方new的是一个新对象,但是remove还是把arraylist中的以有该数据删除,因为关键的地方是contains中判断的就是equals,
      //equals两个数据内容相同则视为同一个元素,remove返回的是boolean。
15         System.out.println(al);
16     }
17     public static ArrayList getSingleElement(ArrayList list) {
18         ArrayList temp = new ArrayList();
19         Iterator it = list.iterator();
20         while(it.hasNext()){
21             Object obj = it.next();
22             //判断被迭代到的元素是否在临时容器中存在
23             if(!temp.contains(obj)){
24                 temp.add(obj);
25             }
26         }
27         return temp;
28     }
29 }

输出:  

[lisi1:21, lisi2:22, lisi3:23, lisi4:24, lisi2:22, lisi3:23]
true
[lisi1:21, lisi3:23, lisi4:24]

LinkedHashSet

HashSet是无序的,但是其下的小弟是有有序功能的,就是LinkedHashSet。

具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。

保证唯一还要有序就直接用LinkedHashSet.就可以实现。

HashSet hs = new LinkedHashSet();

 

|--TreeSet:可以对Set集合中的元素进行排序。是不同步的,即是线程不安全的。

判断元素唯一性的方式:就是根据比较方法compareTo()的返回结果是否是0,是0,就是相同元素,不存。

集合中判断元素不同的方式???

Set中其他的都根据hashcode和equals方法。

TreeSet对元素进行排序的方式一:

让元素自身具备比较功能,就需要实现Comparable接口。覆盖compareTo方法。                                

如果不要按照对象中具备的自然顺序进行排序。如果对象中不具备自然顺序。怎么办?

可以使用TreeSet集合第二种排序方式二:

让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。

将该类对象作为参数传递给TreeSet集合的构造函数。 

TreeSet是排序用的,有排序就需要比较。

public interface Comparable<T>

此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序类的 compareTo 方法被称为它的自然比较方法

 

compareTo

int compareTo(T o)

比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。

 

只要对象需要比较就要实现这个接口。

字符串String 本身就实现了Comparable接口,可以直接进行排序。 

 1 public int compareTo(Object o) {
 2         
 3         Person p = (Person)o;
 4         
 5         int  temp = this.age-p.age;
 6         return temp==0?this.name.compareTo(p.name):temp;
 7 
 8 
 9 
10         int  temp = this.name.compareTo(p.name);
11         return temp==0?this.age-p.age:temp;
12     }

集合自身具有比较性,具有两个才能比。而元素自身具有比较性传一个就能比,元素自身是一个对象。

 TreeSet(Comparator<? super E> comparator)

          构造一个新的空 TreeSet,它根据指定比较器进行排序。

接口 Comparator<T> 

 int

compare(T o1, T o2)
          比较用来排序的两个参数。

compare

int compare(T o1,T o2)

比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数。

 

TreeSet具备比较器,Person具备自然排序,进行元素比较时以TreeSet为主。开发中也是。

java中的很多类都实现了Comparable接口。String,Integer。

凡是一个类具备n多对象的,基本上都实现了这个接口,让其具备比较性。

这个是类的默认比较方式。如果想指定的话最好使用比较器进行。

 

TreeSetDemo.java

TreeSet ts = new TreeSet(new ComparatorByName());

 

让TreeSet集合对象在一开始初始化的时候就具备一个比较器。

 

ComparatorByName.java   

姓名比较器的具体实现:

 1 import java.util.Comparator;
 2 /**
 3  * 创建了一个根据Person类的name进行排序的比较器。
 4  */
 5 public class ComparatorByName implements Comparator {
 6 
 7     @Override
 8     public int compare(Object o1, Object o2) {
 9         Person p1 = (Person)o1;
10         Person p2 = (Person)o2;
11         
12         int temp = p1.getName().compareTo(p2.getName());
13         
14         return temp==0?p1.getAge()-p2.getAge(): temp;
15     }
16 }

根据字符串的长度设置比较器。

ComparatorByLength.java

 1 public class ComparatorByLength implements Comparator {
 2     @Override
 3     public int compare(Object o1, Object o2) {
 4         String s1 = (String)o1;
 5         String s2 = (String)o2;
 6         
 7         int temp = s1.length()-s2.length();
 8         
 9         return temp==0? s1.compareTo(s2): temp;
10     }
11 }

if(this.hashCode()== obj.hashCode() && this.equals(obj))

哈希表确定元素是否相同

1,判断的是两个元素的哈希值是否相同。

    如果相同,在判断两个对象的内容是否相同。

2,判断哈希值相同,其实判断的是对象的hashCode的方法。判断内容相同,用的是equals方法。

注意:如果哈希值不同,是不需要判断equals。


 

 

posted @ 2015-03-08 12:31  SummerChill  阅读(405)  评论(0编辑  收藏  举报