常见Java面试题和答案_第1页
常见Java面试题和答案_第2页
常见Java面试题和答案_第3页
常见Java面试题和答案_第4页
常见Java面试题和答案_第5页
已阅读5页,还剩131页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Interface与AbstractClass的区别

在Java语言中,abstractclass和interface是支持抽象类定义的两种机制。

正是由于这两种机制的存在,才赋予了Java强大的面向对象能力。abstract

class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至

可以相互替换,因此很多开发者在进行抽象类定义时对于abstractclass和

interface的选择显得比较随意。其实,两者之间还是有很大的区别的,对于它

们的选择甚至反映出对于问题领域本质的理解、对于设计意图的理解是否正确、

合理。

AbstractclassInterface

实例

不能不能

i种继承关系,一个类只能使用

类一次继承关系。可以通过继承多一>个类可以实现多个interface

个接口实现多重继承

数据静态的不能被修改即必须是static

可有自己的

成员final,一般不在此定义

可以私有的,非abstract方法,不可有私有的,默认是public,abstract

方法

必须实现类型

可有私有的,默认是friendly不可有私有的,默认是publicstatic

变量型,其值可以在子类中重新定义,final型,且必须给其初值,实现类中不

也可以重新赋值能重新定义,不能改变其值。

设计

表示的是“is-a”关系表示的是“like-a”关系

理念

实现需要继承,要用extends要用implements

abstractclass和interface在Java语言中都是用来进行抽象类(本文中的抽

象类并非从abstractclass翻译而来,它表示的是一个抽象体,而abstract

class为Java语言中用于定义抽象类的一种方法)定义的,那么什么是抽象类,

使用抽象类能为我们带来什么好处呢?

声明方法的存在而不去实现它的类被叫做抽象类(abstractclass),它用于要

创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类

的情况。不能创建abstract类的实例。然而可以创建一个变量,其类型是一个

抽象类,并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。

Abstract类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象

类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这

些方法。

接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。多继承

性可通过实现这样的接口而获得。接口中的所有方法都是抽象的,没有一个有程

序体。接口只可以定义staticfinal成员变量。接口的实现与子类相似,除了

该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序

体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上

调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常

的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof运

算符可以用来决定某对象的类是否实现了接口。

接口可以继承接口。抽象类可以实现(implements)接口,抽象类是可以继承实体

类,但前提是实体类必须有明确的构造函数。接口更关注“能实现什么功能”,

而不管“怎么实现的”。

1.相同点

A.两者都是抽象类,都不能实例化。

B.interface实现类及abstrctclass的子类都必须要实现已经声明的抽象

方法。

2.不同点

A.interface需要实现,要用implements,而abstractclass需要继承,要

用extendso

B.一个类可以实现多个interface,但一个类只能继承一个abstractclass。

C.interface强调特定功能的实现,而abstractclass强调所属关系。

D.尽管interface实现类及abstrctclass的子类都必须要实现相应的抽象

方法,但实现的形式不同。interface中的每一个方法都是抽象方法,都只是声

明的(declaration,没有方法体),实现类必须要实现。而abstractclass的子

类可以有选择地实现。

这个选择有两点含义:

一是Abastractclass中并非所有的方法都是抽象的,只有那些冠有

abstract的方法才是抽象的,子类必须实现。那些没有abstract的方法,在

Abstrctclass中必须定义方法体。

二是abstractclass的子类在继承它时,对非抽象方法既可以直接继承,

也可以覆盖;而对抽象方法,可以选择实现,也可以通过再次声明其方法为抽象

的方式,无需实现,留给其子类来实现,但此类必须也声明为抽象类。既是抽象

类,当然也不能实例化。

E.abstractclass是interface与Class的中介。

interface是完全抽象的,只能声明方法,而且只能声明pulic的方法,不能

声明private及protected的方法,不能定义方法体,也不能声明实例变量。然

而,interface却可以声明常量变量,并且在JDK中不难找出这种例子。但将常

量变量放在interface中违背了其作为接口的作用而存在的宗旨,也混淆了

interface与类的不同价值。如果的确需要,可以将其放在相应的abstractclass

或Class中o

abstractclass在interface及Class中起到了承上启下的作用。一方面,

abstractclass是抽象的,可一以声明抽象方法,以规范子类必须实现的功能;

另一方面,它又可以定义缺省的方法体,供子类直接使用或覆盖。另外,它还可

以定义自己的实例变量,以供子类通过继承来使用。

3.interface的应用场合

A.类与类之前需要特定的接口进行协调,而不在乎其如何实现。

B.作为能够实现特定功能的标识存在,也可以是什么接口方法都没有的纯粹

标识。

C.需要将一组类视为单一的类,而调用者只通过接口来与这组类发生联系。

D.需要实现特定的多项功能,而这些功能之间可能完全没有任何联系。

4.abstractclass的应用场合

一句话,在既需要统一的接口,又需要实例变量或缺省的方法的情况下,就可

以使用它。最常见的有:

A.定义了一组接口,但又不想强迫每个实现类都必须实现所有的接口。可以

用abstractclass定义一组方法体,甚至可以是空方法体,然后由子类选择自

己所感兴趣的方法来覆盖。

B.某些场合下,只靠纯粹的接口不能满足类与类之间的协调,还必需类中表

示状态的变量来区别不同的关系。abstract的中介作用可以很好地满足这一点。

C.规范了一组相互协调的方法,其中一些方法是共同的,与状态无关的,可

以共享的,无需子类分别实现;而另一些方法却需要各个子类根据自己特定的状

态来实现特定的功能。

Public,Private,Protected?default?

方法的访问控制

访问说

不同、、、即符publicprotecteddefaultprivate

情形下、'、、、

同类////

同包///

_______________S__

子类//

通用性/

==、equals的区别?

equals方法(是String类从它的超类Object中继承的)被用来检测两个对象是否相等,即

两个对象的内容是否相等。

==用于比较引用和比较基本数据类型时具有不同的功能:

比较基本数据类型,如果两个值相同,则结果为true

而在比较引用时,如果引用指向内存中的同一对象,结果为true

Eg:sl=newString("sony");〃创建的是字符串对象

sl.equals("sony");〃返回

truesl=="sony"〃返回false

〃如果

si="sony";

si=="sony"〃返回true

常用的JAVA集合及异同

集合指多个元素的聚集体。JavaCollectionsFramework是Java提供的对集合进行

定义,操作,和管理的包含一组接口,类的体系结构。本文对JavaCollectionsFramework

的体系结构作一个全面深入的介绍。

Java集合框架的基本接口/类层次结构:

java.util.Collection[I]

+-java.util.List[I]

+一java.util.ArrayList[C]

+-java.util.LinkedList[C]

+一java.util.Vector[C]

+-java.util.Stack

+-java.util.Set[I]

+-java.util.HashSet[C]

+--java.util.SortedSet[I]

+-java.util.TreeSet[C]

java.util.Map

+-java.util.SortedMap[I]

+--java.util.TreeMap[C]

+-java.util.Hashtable[C]

+--java.util.HashMap[C]

+--java.util.LinkedHashMap[C]

+--java.util.WeakHashMap[C]

[I]:接口

[C]:类

Collection集合

Collection是最基本的集合接口,一个Collection代表一组Object的集合,这些Objcct

被称作Collection的元素。

根据用途的不同,Collection又划分为List与Set。

Collection接口的主要接口方法有:

viewplaincopytoclipboardprint?

publicinterfaceCollection

extendsIterable

〃取得Collection的容量(元素数目)

publicabstractintsize();

〃判断是否为空

publicabstractbooleanisEmpty();

〃判断是否包含某对象元素

publicabstractbooleancontains(Objectobj);

〃取得对所有元素的遍历。可以通过Iterator提供的方法遍历集合的元素

publicabstractIteratoriterator();

〃将集合元素以数据形式返回

publicabstractObject[]toArray();

publicabstractObject[]toArray(Objectaobj[]);

〃向集合体插入•个新的元素

publicabstractbooleanadd(Objectobj);

〃从集合体删除一个元素

publicabstractbooleanremove(Objectobj);

〃是否包含所有collection里的所有元素

publicabstractbooleancontainsAII(Collectioncollection);

〃插入collection里的所有元素

publicabstractbooleanaddAII(Collectioncollection);

〃移除collection里的所有元素

publicabstractbooleanremoveAII(Collectioncollection);

publicabstractbooleanretainAII(Collectioncollection);

〃移除所有元素

publicabstractvoidclear();

//...othermethods

)

该接口定义了集合的基本操作方法。

List集合

List继承自Collection接口。List是一种有序集合,List中的元素可以根据索引(顺序

号:元素在集合中处于的位置信息)进行取得/删除/插入操作。

跟Set集合不同的是,List允许有重复元素。对于满足el.equals(e2)条件的el与e2对象

元素,可以同时存在于List集合中。当然,也有List的实现类不允许重复元素的存在.

同时,List还提供—t'listiterator()方法,返回一个Listiterator接口对象,和Iterator

接口相比,Listiterator添加元素的添加,删除,和设定等方法,还能向前或向后遍历。

List接口添加的主要方法有:

viewplaincopytoclipboardprint?

publicinterfaceList

extendsCollection

(

//...otherCollectionmethods

〃根据索引取得元素

publicabstractObjectget(inti);

〃在指定位置(索引)处插入新的元素

publicabstractObjectset(inti,Objectobj);

〃在List的尾部插入新的元素

publicabstractvoidadd(inti,Objectobj);

〃删除指定位置(索引)处的元素

publicabstractObjectremove(inti);

〃取得指定对象的最开始的索引位置

publicabstractintindexOf(Objectobj);

〃取得指定对象的最后的索引位置

publicabstractintlastlndexOf(Objectobj);

//List提供的新的遍历方法

publicabstractListiteratorlistlterator();

〃从指定位置i处开始迭代。最初next。方法返回的将是位置i处的元素。

publicabstractListiteratorlistlterator(inti);

〃取得从位置i到j的所有元素(包含i但不包含j位置的元素),返回一个新的集合对象。

publicabstractListsubList(inti,intj);

Set集合

Set继承自Collection接口。Set是一种不能包含有重复元素的集合,即对于满足

el.equals(e2)条件的el与e2对象元素,不能同时存在于同一个Set集合里,换句话说,

Set集合里任意两个元素el和e2都满足el.equals(e2)==false条件,Set最多有一-个null

元素。

因为Set的这个制约,在使用Set集合的时候,应该注意:

1,为Set集合里的元素的实现类实现一个有效的equals(Object)方法。

2,对Set的构造函数,传入的Collection参数不能包含重复的元素。

Set接口里定义的方法与Collection基本•样,这里不再重述。

Map集合

Map没有继承Collection接口。也就是说Map和Collection是2种不同的集合。Collection

可以看作是(value)的集合,而Map可以看作是(key,value)的集合。

Map接口山Map的内容提供3种类型的集合视图,,组key集合,■■组value集合,或者・,

组key-value映射关系的集合

Map接口

viewplaincopytoclipboardprint?

publicinterfaceMap

(

//

publicstaticinterfaceEntry

(

publicabstractObjectgetKeyf);

publicabstractObjectgetValue();

publicabstractObjectsetValue(Objectobj);

〃…

)

〃作用基本等同Collection接口的方法

publicabstractintsize();

publicabstractbooleanisEmpty();

publicabstractbooleancontainsKey(Objectobj);

publicabstractbooleancontainsValue(Objectobj);

publicabstractObjectget(Objectobj);

publicabstractObjectput(Objectobj,Objectobjl);

publicabstractObjectremove(Objectobj);

publicabstractvoidclear();

〃添加map里包含的所有元素

publicabstractvoidputAII(Mapmap);

〃key集合

publicabstractSetkeySet();

//value集合

publicabstractCollectionvalues();

//key-value映射关系的集合Set<Entry>

publicabstractSetentrySet();

//...

集合的遍历:

所有java.util.Collection的实现类必须实现

publicabstractIteratoriterator();

方法以支持对所包含的对象进行遍历。

java.util.Iterator[I]

十一一java.util.Listiterator[I]

Iterator接口:

viewplaincopytoclipboardprint?

publicinterfaceIterator

(

〃判断是否存在下一个元素

publicabstractbooleanhasNext();

〃返回下一个可用的元素

publicabstractObjectnext();

〃移除当前元素

publicabstractvoidremove();

Listiterator接口:

viewplaincopytoclipboardprint?

publicinterfaceListiterator

extendsIterator

(

//othermethodsdefinedinIterator

〃判断是否存在上一个元素

publicabstractbooleanhasPrevious();

〃返回上一个可用的元素

publicabstractObjectprevious();

〃取得下一个可用元素的索引位置

publicabstractintnextlndex();

〃取得上一个可用元素的索引位置

publicabstractintpreviouslndex();

〃替换当前位置的元素

publicabstractvoidset(Objectobj);

〃在当前位置插入新元素

publicabstractvoidadd(Objectobj);

对集合操作的工具类

Java提供了java.util.Collections,以及java.util.Arrays类简化对集合的操作

java.util.Collections主要提供一些static方法用来操作或创建Collection,Map等集

合。

java.util.Arrays主要提供static方法对数组进行操作。

ArrayList与LinkedList等的性能比较

JavaCollectionsFramework的List集合类主要有ArrayList,LinkedList,Vector,Stack

等。本文主要对它们作一个比较,说明它们的异同点以及性能上的区别等。

概要

我们在JavaCollectionsFramework-Java集合框架List,Map,Set等全面介绍之概要

篇一文中对Java集合框架(JavaCollectionsFramework)做了一个比较全面的介绍。

该文粗略地介绍了List集合的概念定义等。

List集合

List继承自Collection接口。List是一种有序集合,List中的元素可以根据索引(顺序

号:元素在集合中处于的位置信息)进行取得/删除/插入操作。

跟Set集合不同的是,List允许有重复元素。对于满足el.equals(e2)条件的el与e2对象

元素,可以同时存在于List集合中。当然,也有List的实现类不允许重复元素的存在。

同时,List还提供一个listiterator()方法,返回一个ListIterator接口对象,和Iterator

接口相比,Listiterator添加元素的添加,删除,和设定等方法,还能向前或向后遍历。

List跟Collection的关系:

java.util.Collection[I]

+一一java.util.List[I]

+-java.util.ArrayList[C]

+--java.util.LinkedList[C]

+一java.util.Vector[C]

+--java.util.Stack[C]

List接口的实现类主要有ArrayList,LinkedList,Vector,Stack等。

本文主要对上面提到的几个类作一个比较,说明它们的异同点以及性能上的区别等。

ArrayList,LinkedList,Vector,Stack的相同点

ArrayList,LinkedList,Vector,Stack等类都实现了List接口,都属于List集合。

List接口里定义的基本方法是一样的。

publicinterfaceList

extendsCollection

(

//...otherCollectionmethods

〃根据索引取得元素

publicabstractObjectget(inti);

〃在指定位置(索引)处插入新的元素

publicabstractObjectset(inti,Objectobj);

〃在List的尾部插入新的元素

publicabstractvoidadd(inti,Objectobj);

〃删除指定位置(索引)处的元素

publicabstractObjectremove(inti);

〃取得指定对象的最开始的索引位置

publicabstractintindexOf(Objectobj);

〃取得指定对象的最后的索引位置

publicabstractintlastlndexOf(Objectobj);

//List提供的新的遍历方法

publicabstractListiteratorlistiterator();

〃从指定位置i处开始迭代。最初next()方法返回的将是位置i处的元素。

publicabstractListiteratorlistiterator(inti);

〃取得从位置i到j的所有元素(包含i但不包含j位置的元素),返回一个新的集合

对象。

publicabstractListsubList(inti,intj);

)

ArrayList,LinkedList,Vector,Stack的相异之处:

数据构造上的差异:

ArrayList,Vector,Stack都是使用动态数组来保存集合中的对象元素,亦即ArrayList,

Vector,Stack具有基本相似的数据结构。ArrayList,Vector除了以下所说的线程同步上

的差异之外,它们的功能基本一样;Vector从Stack继承,除了拥有Stack具有的功能之

外,还实现了栈的功能。

而LinkedList则使用链表的形式来保存集合中的对象元素。

线程处理上的差异:

ArrayList,LinkedList没有使用synchronized对线程同步作任何处理,也就是说它们在

同一时刻可以由多个线程访问,不是线程安全的;

Vector,Stack则使用synchronized对主要方法作了同步控制,它们在同一时刻只能由一

个线程访问。

ArrayList.LinkedList,Vector,Stack的性能比较:

因为数据构造上的差异,它们在处理元素的添加,删除,插入,索引取值,遍历取值方面的

效率上也各不相同。

ArrayList,Vector,Stack都是采用动态数组,它们的处理效率基本一样。

LinkedList采用链表构造,所以它跟ArrayList,Vector,Stack在添加,删除,插入,取

值操作上就很大差异。

在具体的应用中,为了性能,功能上的考虑,我们可以根据具体的需求采用不同的List。

ArrayList,Vector,Stack

元素添加操作

ArrayList,Vector,Stack添加元素时的基本步骤是:

-确保动态数组的空间大小。若空间不够时,则为集合元素重新分配空间,新分配的空间是

原有空间大小的L5倍左右,并把原来的集合元素拷贝到新分配的空间上。所以如果对象元

素很多,有可能分配的空间大小要远远多出实际的元素,所以为了内存利用效率考虑,使用

ArrayList等时,如果事先知道元素的多少,最好初始化时为其分配最大空间。

-设置新元素到size+l位置。

大量添加时的性能:因为重新分配空间的次数不会太多,性能评价:好

元素删除操作

-将删除位置i以后的元素全部往前移一个位置

-设置size处元素为null

大量删除时的性能:因为每个元素的删除都会进行移位拷贝,性能评价:差

元素插入操作

-同元素添加操作

-将插入位置i及以后的所有元素往后移一个位置

-设置新元素至插入位置i

大量插入时的性能:因为每个元素的插入都会进行移位拷贝,性能评价:差

索引取值/遍历取值

因为是动态数组结构,所以索引取值(根据数组的下标)的速度非常快。

它们的遍历取值(Iterator,next())的内部实现是根据当前元素的位置取得下一个元素,

所以跟索引取值一样,都是简单地引用数组的下标,所以速度也非常快。

性能评价:极优

LinkedList

元素添加操作

元素删除操作

元素插入操作

LinkedList的元素添加,删除,插入的操作步骤一样:

-定位需要操作的元素

-执行添加,删除,插入操作

虽然在元素的定位操作上需要花些时间,但LinkedList在处理时对元素的定位作了优化,

性能评价:好

索引取值

因为LinkedList的链表结构,所以对元素的索引取值是一个遍历的过程,性能评价:极差

遍历取值

LinkedList在遍历的时候保存了当前元素,因为它的链表结构,可以快速的定位下一个元

素。性能评价:极优

性能总结:

一人itera

add()操delete()操insert操index取值

tor取值

作作作操作

操作

ArrayList/Vector/好差差极极

Stack优优

好好好差极

LinkedList

下面举例来说明它们在性能上的区别。

代码

viewplaincopytoclipboardprint?

packagecom.test.collection;

importjava.util.Iterator;

importjava.util.List;

publicclassTestList{

/**

*List集合性能测试类

*Usage:javacom.test.collection.TestListListClassNameMAX_TIMES

*例:javacom.test.collection.TestListLinkedList100000

*/

publicstaticvoidmain(String[]args){

if(args!=null&&args.length==2){

testList(args[O],Integer.parselnt(args[l]));

}else{

testList("LinkedList",20000);

testList("ArrayList",20000);

)

)

privatestaticvoidtestList(StringlistName,intmaxElements){

Listlist=null;

try(

list=(List)Class.forName("java.util."+listName).newlnstance();

}catch(Exceptione){

e.printStackTrace();

)

addElement2List(list,maxElements);

deleteElement2List(list);

insertElement2List(list/maxements);

getListElementBylndex(list);

getList日ementBylterator(list);

)

//addelementstoList

privatestaticvoidadd日ement2List(Listlist,intmax日ements){

longstart=System.currentTimeMillis();

for(inti=1;i<maxElements;i++){

list.add(newInteger(i));

}

longend=System.currentTimeMillis();

printTime(list,end-start,"[add]H);

//removeelementsfromList

privatestaticvoiddelete日ement2List(Listlist){

longstart=System.currentTimeMillis();

while(!list.isEmpty()){

list.remove(O);

)

longend=System.currentTimeMillis();

printTime(list,end-start,"[delete]");

//insertelementstoList

privatestaticvoidinsert日ement2List(Listlist,intmaxElements){

longstart=System.currentTimeMillis();

for(inti=1;i<maxElements;i++){

list.add(O,newInteger(i));

)

longend=System.currentTimeMillis();

printTime(list,end-start,n[insert]");

)

privatestaticvoidgetListElementBylndex(Listlist){

longstart=System.currentTimeMillis();

for(inti=1;i<list.size();i++){

Integerele=(Integer)list.get(i);

)

longend=System.currentTimeMillis();

printTime(list,end-start,"[index]");

)

privatestaticvoidgetListElementBylterator(Listlist){

longstart=System.currentTimeMillis();

Iteratorite=list.iterator();

while(ite.hasNext()){

Integerele=(lnteger)ite.next();

)

longend=System.currentTimeMillis();

printTime(list/end-start,"[iterator]");

)

privatestaticvoidprintTime(Listlist,longtime,Stringoperation){

Stringout=list.getClass().getSimpleName();

out+=""+operation+"+time;

System.out.println(out);

执行Client,输出结果:

C:\test\list>javacom.test,collection.TestListArrayList100000

ArrayList[add]:79

ArrayList[delete]:8703

ArrayList[insert]:9281

ArrayList[index]:0

ArrayList[iterator]:16

C:\test\list>javacom.test.collection.TestListLinkedList100000

LinkedList[add]:125

LinkedList[delete]:16

LinkedList[insert]:78

LinkedList[index]:80328

LinkedList[iterator]:0

C:\test\list>javacom.test,collection.TestListVector100000

Vector[add]:63

Vector[delete]:8546

Vector[insert]:9422

Vector[index]:16

Vector[iterator]:0

C:\test\list>javacom.test,collection.TestListStack100000

Stack[add]:47

Stack[delete]:8593

Stack[insert]:9610

Stack[index]:0

Stack[iterator]:16

总结:

本文主要比较了ArrayList,Vector,Stack与LinkedList的操作性能。

ArrayList,Vector与Stack在索引取值,迭代取值上有较高的性能。

LinkedList在删除,插入,迭代取值上有较高的性能。

JAVA集合类(大公司面试喜欢问的)

看了一些所谓大公司的JAVA面试问题,发现对于JAVA集合类的使用都比较看重似的,而自

己在这方面还真的是所真甚少,抽空也学习学习吧。

java.util包中就包含了一系列重要的集合类,而对于集合类,主要需要掌握的就是它的内部

结构,以及遍历集合的迭代模式。

接口:Collection

所有集合类的根类型,主要的一个接口方法:booleanadd(Ojbectc)

虽返回的是boolean,但不是表示添加成功与否,因为Collection规定:一个集合拒绝添加

这个元素,无论什么原因,都必须抛出异常,这个返回值表示的意义是add()执行后,集合

的内容是否改了(就是元素有无数量、位置等变化)。类似的addAII,remove,removeAIL

remainAII也是一样的。

用Iterator模式实现遍历集合

Collection有一个重要的方法:iterator。,返回一个Iterator(迭代子),用于遍历集合的所有

元素。Iterator模式可以把访问逻辑从不同类的集合类中抽象出来,从而避免向客户端暴露

集合的内部结构。

for(Iteratorit=c.iterator();it.hasNext();){...}

不需要维护遍历集合的“指针”,所有的内部状态都有Iterator来维护,而这个Iterator山集

合类通过工厂方法生成。

每一种集合类返回的Iterator具体类型可能不同,但它们都实现了Iterator接口,因此,我

们不需要关心到底是哪种Iterator,它只需要获得这个Iterator接口即可,这就是接口的好处,

面向对象的威力。

要确保遍历过程顺利完成,必须保证遍历过程中不更改集合的内容(Iterator的remove。方

法除外),所以,确保遍历可靠的原则是:只在一个线程中使用这个集合,或者在多线程中

对遍历代码进行同步。

JAVAM叩集合类介绍

直接贴链接好了

/article/54/54534.shtm

线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系

列相应的类来实现基本的数据结构。这些类均在java.util包中。本文试图通过简单的描述,

向读者阐述各个类的作用以及如何正确使用这些类。

Collection

|-List

IpLinkedList

卜ArrayList

ILVector

|LStack

LSet

Map

卜Hashtable

[-HashMap

LWeakHashMap

Collection接口

Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素

(Elements)o一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java

SDK不提供直接继承自Collection的类,JavaSDK提供的类都是继承自Collection的“子接口”

如List和Seto

所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于

创建一个空的Collection,有一个Collection参数的构造函数用于创建一个新的Collection,

这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个

Collectiono

如何遍历Collection中的每一个元素?不论Collection的实际类型如何,它都支持一个

iterator。的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问Collection中每一个

元素。典型的用法如下:

Iteratorit=collection.iterator();//获得一个迭代子

while(it.hasNext()){

Objectobj=it.next();//得到下一个元素

)

由Collection接口派生的两个接口是List和Seto

List接口

List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置。用户能够使

用索引(元素在List中的位置,类似于数组下标)来访问List中的元素,这类似于Java的数

组。

和下面要提到的Set不同,List允许有相同的元素。

除了具有Collection接口必备的iterator。方法外,List还提供一个listlterator。方法,返

回一个Listiterator接口,和标准的Iterator接口相比,Listiterator多了•些add()之类的方法,

允许添加,删除,设定元素,还能向前或向后遍历。

实现List接口的常用类有LinkedList,ArrayList,Vector和Stack。

LinkedList类

LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert

方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)

或双向队列(deque)。

注意LinkedList没有同步方法。如果多个线程同时访问个List,则必须自己实现访问

同步。一种解决方法是在创建List时构造一个同步的List:

Listlist=Collections.synchronizedList(newLinkedList(…));

ArrayList类

ArrayList实现了可变大小的数组。它允许所有元素,包括null。ArrayList没有同步。

size,isEmpty,get,set方法运行时间为常数。但是add方法开销为分摊的常数,添加n个

元素需要0(n)的时间。其他的方法运行时间为线性。

每个ArrayList实例都有一个容量(Capacity),即用于存储元素的数组的大小。这个容量

可随着不断添加新元素而自动增加,但是增长算法并没有定义。当需要插入大量元素时,在

插入前可以调用ensureCapacity方法来增加ArrayList的容量以提高插入效率。

和LinkedList一样,ArrayList也是非同步的(unsynchronized)。

Vector类

Vector非常类似ArrayList,但是Vector是同步的。由Vector创建的Iterator,虽然和

ArrayList创建的Iterator是同一接口,但是,因为Vector是同步的,当一个Iterator被创建

而且正在被使用,另一个线程改变了Vector的状态(例如,添加或删除了一些元素),这时

调用Iterator的方法时将抛出ConcurrentModificationException,因此必须捕获该异常。

Stack类

Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector

得以被当作堆栈使用。基本的push和pop方法,还有peek方法得到栈顶的元素,empty方

法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

Set接口

Set是一种不包含重复的元素的Collection,即任意的两个元素el和e2都有

el.equals(e2)=false,Set最多有一个null元素。

很明显,Set的构造函数有一个约束条件,传入的Collection参数不能包含重复的元素。

请注意:必须小心操作可变对象(MutableObject),如果-一个Set中的可变元素改变了

自身状态导致Object.equals(Object);true将导致一些问题。

Map接口

请注意,Map没有继承Collection接口,Map提供key到value的映射。一个Map中不

能包含相同的key,每个key只能映射一个value。Map接口提供3种集合的视图,Map的

内容可以被当作一组key集合,一组value集合,或者--组key-value映射。

Hashtable类

Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的

对象都可作为key或者valueo

添加数据使用put(key,value),取出数据使用get(key),这两个基本操作的时间开销为常

数。

Hashtable通过initialcapacity和loadfactor两个参数调整性能。通常缺省的loadfactor0.75

较好地实现了时间和空间的均衡。增大loadfactor可以节省空间但相应的查找时间将增大,

这会影响像get和put这样的操作。

使用Hashtable的简单示例如下,将1,2,3放到Hashtable中,他们的key分别是“one",”

two","three”:

Hashtablenumbers=newHashtable();

numbers.put(“one”,newInteger(l));

numbers.put(“two”,newlnteger(2));

numbers.put("three”,newlnteger(3));

要取出一个数,比如2,用相应的key:

Integern=(lnteger)numbers.get(“two");

System.out.println(utwo="+n);

山于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何

作为key的对象都必须实现hashCode和equals方法。hashCode和equals方法继承自根类

Object,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个

对象相同,即objl.equals(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,

则它们的hashCode不一定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,

冲突会导致操作哈希表的时间开销增大,所以尽量定义好的hashCode。方法,能加快哈希表

的操作。

如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的

get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和hashCode

方法,而不要只写其中一个。

Hashtable是同步的。

HashMap类

HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即

nullvalue和nullkey。,但是将HashMap视为Collection时(values。方法可返回Collection),

其迭代子操作时间开销和HashMap的容量成比例。因此,如果迭代操作的性能相当重要的

话,不要将HashMap的初始化容量设得过高,或者loadfactor过低。

WeakHashMap类

WeakHashMap是一种改进的HashMap,它对key实行“弱引用”,如果一个key不再被

外部所引用,那么该key可以被GC回收。

总结

如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该

使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList«

如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率

较高,如果多个线程可能同时操作一个类,应该使用同步的类。

要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。

尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换

成LinkedList时,客户端代码不用改变。这就是针对抽象编程。

java.util中的集合类包含Java中某些最常用的类。最常用的集合类是List和Map。List

的具体实现包括ArrayList和Vector,它们是可变大小的列表,比较适合构建、存储和操作

任何类型对象的元素列表。List适用于按数值索引访问元素的情形。

Map提供了一个更通用的元素存储方法•M叩集合类用于存储元素对(称作"键"和"值"),

其中每个键映射到•个值。从概念上而言,您可以将List看作是具有数值键的Map。而

实际上,除了List和Map都在定义java.util中外,两者并没有直接的联系。本文将着重

介绍核心Java发行套件中附带的Map,同时还将介绍如何采用或实现更适用于您应用程

序特定数据的专用M叩。

了解Map接口和方法

Java核心类中有很多预定义的M叩类.在介绍具体实现之前,我们先介绍一下Map接

口本身,以便了解所有实现的共同点。Map接口定义了四种类型的方法,每个Map都包

含这些方法。下面,我们从两个普通的方法(表1)开始对这些方法加以介绍。

表1:覆盖的方法。我们将这Object的这两个方法覆盖,以正确比较Map对象的等价

性。

equals(Objecto)比较指定对象与此Map的等价性

hashCode()返回此Map的哈希码

Map构建

Map定义了几个用于插入和删除元素的变换方法(表2)»

表2:Map更新方法:可以更改Map内容。

clear()从Map中删除所有映射

remove(Objectkey)从Map中删除键和关联的值

put(Objectkey,Objectvalue)将指定值与指定键相关联

clear()从Map中删除所有映射

putAII(Mapt)将指定Map中的所有映射复制到此map

尽管您可能注意到,纵然假设忽略构建一个需要传递给的的开销,使用

PutAII()Map

putAIIO通常也并不比使用大量的put()调用更有效率,但putAII()的存在一点也不稀奇。

这是因为,putAIIO除了迭代put()所执行的将每个键值对添加到Map的算法以外,还需

要迭代所传递的Map的元素。但应注意,putAIIO在添加所有元素之前可以正确调整Map

的大小,因此如果您未亲自调整Map的大小(我们将对此进行简单介绍),贝IJputAII()可

能比预期的更有效。

查看Map

迭代Ma

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论