JAVA学习- 集合接口

  • Post author:
  • Post category:java




一、Collection集合接口

在之前学习链表的时候可以发现,当使用add()方法向链表增加数据的时候,每次保存的都是一个对象的数据,而Collection操作过程之中每次也只能够保存一个对象。在Collection接口之中一共定义了15个方法,那么常用的方法如下:


No.


方法名称


类型


描述


1


public boolean add(E e)


普通


向集合之中保存数据

2

public void clear()

普通

清空集合

3

public boolean contains(Object o)

普通

查询集合之中是否包含有指定对象,需要equals()

4

public boolean remove(Object o)

普通

删除对象,需要equals()

5

public boolean isEmpty()

普通

判断集合是否为空集合

6

public int size()

普通

取得集合的长度

7

public Object[] toArray()

普通

将集合以对象数组的形式返回


8


public Iterator iterator()


普通





Iterator


接口实例化

在以上所给出的方法之中,99%的情况下是使用add()、iterator()两个方法,其它的方法都很少使用。但是在开发之中不会去直接使用Collection(时代已经结束了),都会使用Collection下的两个子接口:List(允许重复)、Set(不允许重复)。



二、List集合接口

List接口是Collection之中最为常用的子接口,也是大家在开发过程之中主要使用的接口。但是List子接口针对于Collection子接口做了大量的功能扩充,而主要扩充的方法有如下几个:


No.


方法名称


类型


描述


1


public E get(int index)


普通


取得指定索引位置上的对象

2

public E set(int index, E element)

普通

修改指定索引位置上的对象

3

public ListIterator listIterator()

普通

为ListIterator接口实例化

那么接口完成后如果要想使用接口那么一定需要子类,而常用的两个子类:ArrayList、Vector。

1、新的子类:ArrayList(90%)

ArrayList是在JDK 1.2之后引入的,或者更加明确的讲像Collection、List等都是JDK 1.2之后引入的,也是在List接口使用过程之中最为常见的一个子类。


范例:

使用ArrayList


package

cn.mldn.demo;


import

java.util.ArrayList;


import

java.util.List;


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

List all =

new

ArrayList() ;

all.add(“HELLO”) ;

all.add(“HELLO”) ;  // 保存了重复数据

all.add(“WORLD”) ;

System.


out


.println(all);

}

}

但是在很多时候可以采用循环的方式输出,因为在List子接口里面扩充了一个get()方法,所以就可以使用for循环。


范例:

循环输出List集合


package

cn.mldn.demo;


import

java.util.ArrayList;


import

java.util.List;


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

List all =

new

ArrayList() ;

all.add(“HELLO”) ;

all.add(“HELLO”) ;  // 保存了重复数据

all.add(“WORLD”) ;


for

(

int

x = 0; x < all.size(); x++) {

System.


out


.println(all.get(x));

}

}

}


范例:

验证其它方法


package

cn.mldn.demo;


import

java.util.ArrayList;


import

java.util.List;


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

List all =

new

ArrayList() ;

System.


out


.println(all.isEmpty());

all.add(“HELLO”) ;

all.add(“HELLO”) ;  // 保存了重复数据

all.add(“WORLD”) ;

System.


out


.println(all.isEmpty());

all.set(0, “hello”) ;   // 此方法也是List扩充

all.remove(“WORLD”) ;

System.


out


.println(all);

}

}

但是以上的程序之中发现操作的数据类型都是String,那么String类是一个比较完善的类,那么下面使用一个自定义的类进行操作。


范例:

保存自定义类对象


package

cn.mldn.demo;


import

java.util.ArrayList;


import

java.util.List;


class

Person {


private

String name ;


private


int

age ;


public

Person(String name,

int

age) {


this

.name = name ;


this

.age = age ;

}

@Override


public

String toString() {


return

“姓名:” +

this

.name + “,年龄 :” +

this

.age + “\n” ;

}

@Override


public


boolean

equals(Object obj) {


if

(obj ==

null

) {


return


false

;

}


if

(

this

== obj) {


return


true

;

}


if

(!(obj

instanceof

Person)) {


return


false

;

}

Person per = (Person) obj ;


if

(per.name.equals(

this

.name) && per.age ==

this

.age) {


return


true

;

}


return


false

;

}

}


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

List all =

new

ArrayList() ;

all.add(

new

Person(“张三”,20)) ;

all.add(

new

Person(“李四”,21)) ;

all.add(

new

Person(“王五”,19)) ;

all.remove(

new

Person(“王五”,19)) ;  // 删除

System.


out


.println(all.contains(

new

Person(“李四”,21)));

System.


out


.println(all);

}

}

那么在之前使用的链表操作,在List接口上可以方便的使用,使用的规则与之前完全一样,可是List所采用的程序的逻辑更加合理,性能更好,所以不会使用自定义链表,都会使用List接口操作。

2、旧的子类:Vector(10%)

Vector是从JDK 1.0的时候引入的操作类,最早是用于纯粹的保存多个对象,同时在JDK 1.2之后为了让其可以继续使用,于是让Vector类多实现了一个List接口,所以List接口下有两个常用的子类:ArrayList、Vector。

既然Vector也是List接口的子类,所以在使用上,不管使用ArrayList还是Vector不会有任何的区别。


范例:

验证Vector


package

cn.mldn.demo;


import

java.util.List;


import

java.util.Vector;


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

List all =

new

Vector() ;

all.add(“HELLO”) ;

all.add(“HELLO”) ;  // 保存了重复数据

all.add(“WORLD”) ;

System.


out


.println(all);

}

}


面试题:

请解释ArrayList和Vector区别?


No.


区别


ArrayList


Vector

1

推出时间

JDK 1.2时推出

JDK 1.0时推出

2

性能

采用异步处理方式,性能较高

采用同步处理方式,性能较低

3

安全性

数据安全性差

数据安全性高

4

输出

Iterator、ListIterator、foreach

Iterator、ListIterator、foreach、Enumeration

考虑到日后的开发异步开发居多,所以以ArrayList类为主。



三、Set集合接口

Set之中保存的元素是不能够有重复,但是Set接口并不像List接口那样对Collection进行了方法的扩充,而是完整的继承了Collection接口的所有方法,那么也就意味着,在之前使用的get()方法无法使用了。

Set子接口之中重要使用两个常用的子类:HashSet、TreeSet。

1、散列存放的子类:HashSet(90%)

Hash是一种散列算法,指的保存数据没有序列。


package

cn.mldn.demo;


import

java.util.HashSet;


import

java.util.Set;


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

Set all =

new

HashSet() ;

all.add(“HELLO”) ;

all.add(“HELLO”) ;  // 保存了重复数据

all.add(“WORLD”) ;

all.add(“小金子”) ;

all.add(“小谢子”) ;

System.


out


.println(all);

}}

使用HashSet是不能够保存重复数据的。而且保存的数据没有任何的顺序。

2、排序存放的子类:TreeSet(10%)

如果希望里面的数据排序,则可以使用TreeSet子类。


package

cn.mldn.demo;


import

java.util.Set;


import

java.util.TreeSet;


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

Set all =

new

TreeSet() ;

all.add(“B”) ;

all.add(“D”) ;  // 保存了重复数据

all.add(“E”) ;

all.add(“A”) ;

all.add(“C”) ;

System.


out


.println(all);

}}

但是对于排序一般意义不大,所以使用的时候还是以HashSet为主。

3、关于数据排序的说明

使用TreeSet可以实现集合中数据排序的保存,那么在之前使用的是String型数据,下面使用自定义类。但是这个类如果要想正常的使用TreeSet保存,那么一定要在此类上实现java.lang.Comparable接口,以区分大小。

但是在此时覆写compareTo()方法的时候必须注意到:所有的属性都必须进行比较,否则就会出现部分属性内容相同也会认为是同一对象的情况,造成数据的保存错误。


范例:

使用自定义类


package

cn.mldn.demo;


import

java.util.Set;


import

java.util.TreeSet;


class

Person

implements

Comparable {


private

String name ;


private


int

age ;


public

Person(String name,

int

age) {


this

.name = name ;


this

.age = age ;

}

@Override


public

String toString() {


return

“姓名:” +

this

.name + “,年龄 :” +

this

.age + “\n” ;

}

@Override


public


int

compareTo(Person o) {


if

(

this

.age > o.age) {


return

-1 ;

}

else


if

(

this

.age < o.age) {


return

1 ;

}


return


this

.name.compareTo(o.name);

}

}


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

Set all =

new

TreeSet() ;

all.add(

new

Person(“张三”,20)) ;

all.add(

new

Person(“李四”,21)) ;

all.add(

new

Person(“赵六”,21)) ; // 年龄重复

all.add(

new

Person(“王五”,19)) ;

all.add(

new

Person(“王五”,19)) ; // 彻底重复

System.


out


.println(all);

}

}

通过此时的程序也可以得出一个结论:TreeSet使用过程之中一定要使用到Comparable接口,而且TreeSet集合里面是依靠Comparable接口的compareTo()方法返回的数据来区分是否为重复数据。

4、关于重复数据的说明

Set子接口之中不允许保留重复数据,之前使用的TreeSet子类虽然依靠了Comparable接口进行重复数据判断,但是此判断的方式也只是针对于TreeSet这种排序结构起作用,而

真正意义上的排序操作是不依靠接口的,而是依靠


Object


类之中的两个方法:




·


取得对象的


hash


码:


public int hashCode()






·


对象比较:


public boolean equals(Object obj)






在判断对象是否重复的过程之中,其基本流程如下:




·


首先使用要查询对象的


hashCode


与集合之中的保存对象的每一个


hashCode


进行比较;




·


如果


hashCode


相同,则再使用


equals()


方法进行内容的比较。



01500097_MLDN-魔乐科技-李兴华【Java核心技术】_Set集合接口



01500097_MLDN-魔乐科技-李兴华【Java核心技术】_Set集合接口


范例:

重复对象判断


package

cn.mldn.demo;


import

java.util.HashSet;


import

java.util.Set;


class

Person {


private

String name ;


private


int

age ;


public

Person(String name,

int

age) {


this

.name = name ;


this

.age = age ;

}

@Override


public

String toString() {


return

“姓名:” +

this

.name + “,年龄 :” +

this

.age + “\n” ;

}

@Override


public


int

hashCode() {


final


int

prime = 31;


int

result = 1;

result = prime * result + age;

result = prime * result + ((name ==

null

) ? 0 : name.hashCode());


return

result;

}

@Override


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

(age != other.age)


return


false

;


if

(name ==

null

) {


if

(other.name !=

null

)


return


false

;

}

else


if

(!name.equals(other.name))


return


false

;


return


true

;

}

}


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

Set all =

new

HashSet() ;

all.add(

new

Person(“张三”,20)) ;

all.add(

new

Person(“李四”,21)) ;

all.add(

new

Person(“赵六”,21)) ; // 年龄重复

all.add(

new

Person(“王五”,19)) ;

all.add(

new

Person(“王五”,19)) ; // 彻底重复

System.


out


.println(all);

}

}

任何情况下如果是对象的重复判断,永恒都使用hashCode()和equals()。



四、Map集合接口

Collection每次只能够保存一个对象,而Map每次可以保存一对对象。那么这对对象会按照“key=value”的形式进行存储,随后可以通过key找到对应的value,就好比电话号码本一样,例如,现在存了如下数据:

· name = 张三,tel = 110;

· name = 李四,tel = 119;

现在找到了张三(找到了name),就可以找到与之对应的电话(tel),而这样的操作可以通过Map集合表示(public interface Map)。在使用Map接口的时候需要设置两个泛型类型,一个是key的类型,另外一个是value的类型,而在Map接口中定义了如下常用方法。


No.


方法名称


类型


描述


1


public V put(K key, V value)


普通


集合之中保存数据


2


public V get(Object key)


普通


根据


key


取得对应的


value

3

public Set keySet()

普通

取得全部的key,key不能重复

4

public Collection values()

普通

取得全部的value


5


public Set> entrySet()


普通





Map


集合变为


Set


集合

而在Map接口下又有两个常见的子类:HashMap、Hashtable。

1、新的子类:HashMap(90%)

HashMap是Map接口中最为常用的一个子类,下面将使用HashMap验证Map的使用操作。


范例:

保存数据


package

cn.mldn.demo;


import

java.util.HashMap;


import

java.util.Map;


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

Map map =

new

HashMap();

map.put(1, “张三”);

map.put(1, “李四”); // key重复

map.put(2, “王五”);

map.put(3,

null

);

map.put(

null

, “赵六”);

System.


out


.println(map);

}

}

在使用Map集合的时候如果发生了key重复的问题,那么会使用新的值替换掉旧的值。但是从实际来讲,设置在Map之中的数据主要是为了查找使用。


Collection


设置数据的目的主要是为了输出,而


Map


设置数据的目的主要是为了查找。


范例:

查找数据


package

cn.mldn.demo;


import

java.util.HashMap;


import

java.util.Map;


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

Map map =

new

HashMap();

map.put(1, “张三”);

map.put(1, “李四”); // key重复

map.put(2, “王五”);

map.put(3,

null

);

map.put(

null

, “赵六”);

System.


out


.println(map.get(1));

System.


out


.println(map.get(

null

));

System.


out


.println(map.get(200));   // 没有返回null

}

}

整个过程之中都是可以进行null操作的。

2、旧的子类:Hashtable(10%)

Hashtable与Vector、Enumeration一样,都是最早提供的集合操作类,在JDK 1.2之后为了保护其可以继续使用,所以让Hashtable多实现了一个Map接口。


范例:

验证Hashtable


package

cn.mldn.demo;


import

java.util.Hashtable;


import

java.util.Map;


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

Map map =

new

Hashtable();

map.put(1, “张三”);

map.put(1, “李四”); // key重复

map.put(2, “王五”);

System.


out


.println(map.get(1));

System.


out


.println(map.get(200));   // 没有返回null

}

}

在Hashtable的操作之中可以发现,里面是不能够存在有null数据的。


面试题:

请解释HashMap和Hashtable区别?


No.


区别


HashMap


Hashtable

1

推出时间

JDK 1.2时推出

JDK 1.0时推出

2

性能

采用异步处理方式,性能较高

采用同步处理方式,性能较低

3

安全性

数据安全性差

数据安全性高

4

处理null

允许保存null

不允许保存null,会出现NullPointerException

考虑到日后的开发异步开发居多,所以以HashMap类为主。

3、关于Map集合的输出说明(核心)

在Map接口里面存在有一个keySet()的方法,此方法返回的是所有的key的数据,并且是以Set集合的形式返回,于是下面就使用此方法输出数据。


package

cn.mldn.demo;


import

java.util.HashMap;


import

java.util.Iterator;


import

java.util.Map;


import

java.util.Set;


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

Map map =

new

HashMap();

map.put(1, “张三”);

map.put(2, “李四”);

map.put(3, “王五”);

Set set = map.keySet() ;   // 取得全部的key

Iterator iter = set.iterator() ;


while

(iter.hasNext()) {

Integer key = iter.next() ;

System.


out


.println(key + ” –> ” + map.get(key));

}

}

}

就本程序而言,已经实现了Map集合的输出操作,但是这个输出操作存在以下问题:首先取得了全部key,需要进行迭代输出,而且每一个key又要去查询集合中对应的value(循环),所以这样的输出形式是不可取的。

如果要想输出Map集合,那么一定还是需要使用到Iterator接口,可是Map接口里面并没有定义像Collection接口之中定义的iterator()方法,那么下面就需要分析一下Collection和Map的数据保存区别。


01500099_MLDN-魔乐科技-李兴华【Java核心技术】_Map集合接口

可以发现在Map接口里面存在有一个static定义的子接口:Map.Entry,而所有的key和value都自动的封装在了此接口对象之中,而在

Map.Entry


接口里面存在有两个方法:




·


取得包装的


key





public K getKey()






·


取得包装的


value





public V getValue()




关于


Map


接口使用


Iterator


输出的过程:

1、   首先使用Map集合之中的entrySet()方法将Map集合变为Set集合,而此时Set集合中的每一个元素类型都是Map.Entry接口实例;

2、   利用Set接口的iterator()方法取得Iterator接口对象,同时Iterator中操作的类型依然是Map.Entry;

3、   利用Iterator进行迭代输出,取出每一个Map.Entry对象,并且利用getKey()和getValue()方法取出数据。


范例:

利用Iterator输出Map集合


package

cn.mldn.demo;


import

java.util.HashMap;


import

java.util.Iterator;


import

java.util.Map;


import

java.util.Set;


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

Map map =

new

HashMap();

map.put(1, “张三”);

map.put(2, “李四”);

map.put(3, “王五”);

Set> set = map.entrySet();

Iterator> iter = set.iterator();


while

(iter.hasNext()) {

Map.Entry me = iter.next();

System.


out


.println(me.getKey() + ” –> ” + me.getValue());

}

}

}

这一程序在工作之中一定会出现,建议下面多写几次,同时一定要记住Map.Entry的作用。

4、关于Map集合之中key的说明

通过之前的代码演示发现一直都是使用Integer作为key的类型,而且Integer本身也是系统类。那么在实际上Map也可以使用自定义类型作为key。但是此时必须有一个要求:由于map集合根据key的查找属于对象的匹配过程,所以作为自定义的key类型,类一定要覆写Object类的hashCode()和equals()两个方法。


package

cn.mldn.demo;


import

java.util.HashMap;


import

java.util.Map;


class

Person {


private

String name ;


private


int

age ;


public

Person(String name,

int

age) {


this

.name = name ;


this

.age = age ;

}

@Override


public

String toString() {


return

“姓名:” +

this

.name + “,年龄:” +

this

.age ;

}

@Override


public


int

hashCode() {


final


int

prime = 31;


int

result = 1;

result = prime * result + age;

result = prime * result + ((name ==

null

) ? 0 : name.hashCode());


return

result;

}

@Override


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

(age != other.age)


return


false

;


if

(name ==

null

) {


if

(other.name !=

null

)


return


false

;

}

else


if

(!name.equals(other.name))


return


false

;


return


true

;

}

}


public


class

TestDemo {


public


static


void

main(String[] args)

throws

Exception {

Map map =

new

HashMap();

map.put(

new

Person(“张三”, 20),

new

String(“ZS”));

System.


out


.println(map.get(

new

Person(“张三”, 20)));

}

}

以上的代码只是在一次重复强调了hashCode()和equals()的作用,但是从实际的角度来看,作为key的类型99%的情况下都会使用

String


表示

,或者使用Integer等系统类表示。

转载于:https://www.cnblogs.com/kvikon/p/4676518.html