JAVA经典面试题+答案(共18页).docx
精选优质文档-倾情为你奉上1 forword和redirect的区别以及各自的应用场景直接转发方式(Forward),客户端和浏览器只发出一次请求,Servlet、HTML、JSP或其它信息资源,由第二个信息资源响应该请求,在请求对象request中,保存的对象对于一个每个信息资源是共享的。 场景:Web应用程序大多会有一个控制器。由控制器来控制请求应该转发给那个信息资源。然后由这些信息资源处理请求,处理完以后还可能转发给另外的信息资源来返回给用户,这个过程就是经典的MVC模式。间接转发方式(Redirect)实际是两次HTTP请求,服务器端在响应第一次请求的时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的。场景:一般用于避免用户的非正常访问。例如:用户在没有登录的情况下访问后台资源,Servlet可以将该HTTP请求重定向到登录页面,让用户登录以后再访问。区别Forward和Redirect代表了两种请求转发方式:直接转发和间接转发。对应到代码里,分别是RequestDispatcher类的forward()方法和HttpServletRequest类的sendRedirect()方法。 对于间接方式,服务器端在响应第一次请求的时候,让浏览器再向另外一个URL发出请求,从而达到转发的目的。它本质上是两次HTTP请求,对应两个request对象。对于直接方式,客户端浏览器只发出一次请求,Servlet把请求转发给Servlet、HTML、JSP或其它信息资源,由第2个信息资源响应该请求,两个信息资源共享同一个request对象。2 Spring套餐1、 描述Spring容器初始化过程Ioc容器的初始化是由refresh()方法来启动的,这个方法标志着Ioc容器的正式启动。具体来说这个启动过程包括三个基本过程:1>.BeanDifinition的Resource定位指的是BeanDifinition的资源定位,它由ResourceLoader通过统一的Resource接口来完成,这些BeanDifinition的存在形式,比如,在文件系统中的Bean定义信息可以使用FileSystemResource来进行抽象,在类路径中的Bean定义信息可以使用ClassPathResource。2>.BeanDifinition的载入与解析把用户定义好的Bean表示成Ioc容器内部的数据结构,而这个容器内部的数据结构就是BeanDifinition。具体来说,BeanDifinition实际上就是POJO对象在IOC容器中的抽象,通过这个BeanDifinition定义的数据结构,使IOC容器能够方便的对POJO对象也就是Bean进行管理。3>.BeanDifinition在Ioc容器中的注册这个操作是通过调用BeanDifinitionRegistry借口来实现的。这个注册过程把载入过程中解析得到的BeanDifinition向Ioc容器进行注册。 在阅读源码中可知,在IOC容器内部将BeanDifinition注入到一个HashMap中去,Ioc容器就是通过这个HashMap来持有这些BeanDifinition数据的。2、为什么要进行事务管理,Spring是如何进行事务管理支持的Spring事务是 Spring AOP 的一种实现,本质是基于动态代理技术对所需要管理的bean进行加载,并在方法调用前后加入合适的事务管理代码实现事务的提交与产生异常时回滚。spring的事务声明有两种方式,编程式和声明式。spring主要是通过“声明式事务”的方式对事务进行管理,即在配置文件中进行声明,通过AOP将事务切面切入程序,最大的好处是大大减少了代码量。3、 Spring如何配置数据库驱动<bean id="dataSource" class="mons.dbcp.BasicDataSource"><property name="driverClassName" value="com.mysql.jdbc.Driver"></property><property name="url" value="jdbc:mysql:/localhost:3306/test"></property><property name="username" value="root"></property><property name="password" value="admin"></property></bean>4、 解释一下DI依赖注入和IOC控制反转,Spring中是如何做的 IOC(控制反转)是spring的核心,由Spring管理创建响应的对象,即由IOC容器帮对象管理响应的依赖关系,并在运行时将对象注入,而不是通过传统的new来主动创建对象。而DI则是实现IOC注入关联对象的方式,有三种:set方法注入、构造函数注入和参数(常量)注入。控制反转和依赖注入是同一个东西在不同的角度进行分析,在实际项目开发中我们需要把bean都放在spring中管理,告诉spring不同bean之间的依赖关系,而具体的创建注入都是由spring容器帮我们实现的,即通过控制反转和依赖注入,本质实现都是基于反射机制来实现的。5、 Spring中的BeanFactory与ApplicationContext的作用有那些BeanFactory提供了配制框架及基本功能,负责对象实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。而ApplicationContext则增加了更多支持企业核心内容的功能。比如更易与Spring AOP集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的context实现(如针对web应用的WebApplicationContext)。6、 Spring中的核心类有那些,各有什么作用BeanFactory:产生一个新的实例,可以实现单例模式BeanWrapper:提供统一的get及set方法ApplicationContext:提供框架的实现,包括BeanFactory的所有功能7、 什么是aop,aop的作用是什么面向切面编程,或AOP允许程序员模块化横向业务逻辑,将系统中非核心的业务提取出来,进行单独处理,解决系统代码耦合度过高的问题。使代码重用度高、易于维护。例如权限认证、日志管理和事务管理。8、 spring bean的创建方式和生命周期三种创建方式:构造器注入创建 工厂方法(静态工厂) 工厂类(实例工厂)1) Bean实例化 :Bean的默认构造函数。 2) Bean的初始化:Init()方法中可以进行初始化。 3) Bean的使用 :getBean()方法可以获取当前的Bean,从而做相对应的业务操作。 4) Bean的销毁 :destroy()方法执行bean的销毁。 9、spring与springMVC的区别Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。spring mvc类似于struts的一个MVC开框架,其实都是属于spring,spring mvc需要有spring的架包作为支撑才能跑起来。3 HashMap(或者Hashtable/ArrayList。)的数据结构(实现方式)HashMap: key:value底层使用数组(table)+链表(entry)结构,通过key进行二次hash计算出的hashCode%table.length确定对应的数组下标的位置存放value。HashTable:key:valueHashtable 继承于Dictionary,实现了Map、Cloneable、Java.io.Serializable接口,Hashtable 的函数都是同步的,这意味着它是线程安全的。它的key、value都不可以为null。此外,Hashtable中的映射不是有序的。底层使用数组(table)+链表(entry)结构,hash计算方法是直接使用key的hashcode对table数组的长度直接进行取模。ArrayList:线性链表(线程不安全),最核心的两个成员变量是存储数据的数组和数组大小。 a. ArrayList 是通过将底层 Object 数组复制的方式(System.arraycopy方法)来处理数组的增长; b. 当ArrayList 的容量不足时,其扩充容量的方式:先将容量扩充至当前容量的1.5倍,若还不够,则将容量扩充至当前需要的数量。4 GET与POST的区别,分别用在什么场景合适?GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。get是把参数数据队列加到提交表单的ACTION属性所指的URL中,值和表单内各个字段一一对应,在URL中可以看到。post是通过HTTP post机制,将表单内各个字段与其内容放置在HTML HEADER内一起传送到ACTION属性所指的URL地址。用户看不到这个过程。对于get方式,服务器端用doGet获取变量的值,对于post方式,服务器端用doPost获取提交的数据。get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。get安全性非常低,post安全性较高。但是执行效率却比Post方法好。 5什么是单例模式,有哪些实现方式,写出其中两种Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问,并且提供一个全局的访问点。第一种(懒汉,线程不安全):略(参考第二种)第二种(懒汉,线程安全): public class Singleton private static Singleton instance; private Singleton () public static synchronized Singleton getInstance() if (instance = null) instance = new Singleton(); return instance; 这种写法能够在多线程中很好的工作,而且看起来它也具备很好的lazy loading,但是,遗憾的是,效率很低,99%情况下不需要同步。第三种(饿汉): public class Singleton private static Singleton instance = new Singleton(); private Singleton () public static Singleton getInstance() return instance; 第四种(静态内部类): public class Singleton private static class SingletonHolder private static final Singleton INSTANCE = new Singleton(); private Singleton () public static final Singleton getInstance() return SingletonHolder.INSTANCE; 这种方式同样利用了classloder的机制来保证初始化instance时只有一个线程,它跟第三种方式不同的是(很细微的差别):第三种是只要Singleton类被装载了,那么instance就会被实例化(没有达到lazy loading效果),而这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance。想象一下,如果实例化instance很消耗资源,我想让他延迟加载,另外一方面,我不希望在Singleton类加载时就实例化,因为我不能确保Singleton类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化instance显然是不合适的。这个时候,这种方式相比第三方式就显得很合理。第五种(枚举): public enum Singleton INSTANCE; public void instance() 这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。第六种(双重校验锁): public class Singleton private volatile static Singleton singleton; private Singleton () public static Singleton getSingleton() if (singleton = null) synchronized (Singleton.class) if (singleton = null) singleton = new Singleton(); return singleton; 这个是第二种方式的升级版,俗称双重检查锁定,但仅在JDK1.5之后有效。6 常见的设计模式有哪些,并写出简单的示例代码单例模式(略):工厂模式(普通、多方法和静态工厂方法、抽象工厂):该模式主要功能是统一提供实例对象的引用建造者模式:一个对象的组成可能有很多其他的对象一起组成的,比如说,一个对象的实现非常复杂,有很多的属性,而这些属性又是其他对象的引用,可能这些对象的引用又包括很多的对象引用。封装这些复杂性,就可以使用建造模式。策略模式:这个模式是将行为的抽象,即当有几个类有相似的方法,将其中通用的部分都提取出来,从而使扩展更容易。门面模式:这个模式个人感觉像是Service层的一个翻版。比如Dao我们定义了很多持久化方法,我们通过Service层将Dao的原子方法组成业务逻辑,再通过方法向上层提供服务。门面模式道理其实是一样的。代理模式:其实每个模式名称就表明了该模式的作用,代理模式就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做,此处的代理就是这个意思。7 原生JS的继承是怎么实现的,都有哪几种?对象冒充function Parent(username).function Child(username,password)/第一步:this.method是作为一个临时的属性,并且指向Parent所指向的对象,this.method = Parent;/第二步:执行this.method方法,即执行Parent所指向的对象函数this.method(username);/最关键的一行/第三步:销毁this.method属性,即此时Child就已经拥有了Parent的所有属性和方法delete this.method;. call方法call方法是Function类中的方法call方法的第一个参数的值赋值给类(即方法)中出现的thiscall方法的第二个参数开始依次赋值给类(即方法)所接受的参数function Parent(username).function Child(username,password)Parent.call(this,username);.apply()方法方式 apply方法接受2个参数, A、第一个参数与call方法的第一个参数一样,即赋值给类(即方法)中出现的this B、第二个参数为数组类型,这个数组中的每个元素依次赋值给类(即方法)所接受的参数function Parent(username).function Child(username,password)Parent.apply(this,new Array(username);.原型链方式,即子类通过prototype将所有在父类中通过prototype追加的属性和方法都追加到Child,从而实现了继承。function Person()Person.prototype.hello = "hello"Person.prototype.sayHello = function()alert(this.hello);function Child() Child.prototype = new Person();/这行的作用是:将Parent中将所有通过prototype追加的属性和方法都追加到Child,从而实现了继承 Child.prototype.world = "world" Child.prototype.sayWorld = function()alert(this.world);混合方式(略):混合了call方式、原型链方式8 数据库优化方式有哪些?(下面是可能会连贯性问到的问题)1. MySQL和Oracle的区别,在什么情况下更适合?MySQL开源免费,适合中小型应用系统,ORACLE庞大健全用于大型应用系统和安全性要求较高的领域。使用细节也有些区别,例如:mysql中组函数在select语句中可以随意使用,但在oracle中如果查询语句中有组函数,那其他列名必须是组函数处理过的,或者是group by子句中的列否则报错select name,count(money) from user;这个放在mysql中没有问题在oracle中就有问题了。自动增长列的实现MYSQL有自动增长的数据类型,插入记录时不用操作此字段,会自动获得数据值。ORACLE没有自动增长的数据类型,需要建立一个自动增长的序列号,插入记录时要把序列号的下一个值赋于此字段。单引号处理MYSQL里可以用双引号包起字符串,ORACLE里只可以用单引号包起字符串。分页处理MYSQL使用limit即可,ORACLE必须使用三层子查询结合ROWNUM实现日期字段MYSQL日期字段分DATE和TIME两种,ORACLE日期字段只有DATE,包含年月日时分秒信息,用当前数据库的系统时间为SYSDATE,精确到秒。空字符串MYSQL的非空字段也有空的内容,ORACLE里定义了非空字段就不容许有空的内容。按MYSQL的NOT NULL来定义ORACLE表结构,导数据的时候会产生错误。因此导数据时要对空字符进行判断,如果为NULL或空字符,需要把它改成一个空格的字符串。2. MySQL的性能方面你了解多少?比如一个正常的读写操作你觉得多少时间算是正常?服务器12核24线程,64G内存,SATA盘的情况下:读1.53W/s,写400010000/s,TPS 8001500/s。,平均响应10ms以内正常。3. 如果一张表的查询速度慢了.你会从哪些方面去优化?慢查询定位及改进:Show命令、慢查询日志、explain分析查询、profiling分析索引优化合理建立索引、优化索引相关的查询SQL1>. 当结果集只有一行数据时使用LIMIT 12>. 避免SELECT *,始终指定你需要的列3>. 使用连接(JOIN)来代替子查询(Sub-Queries)4>. 使用合理的字段属性长度5>. 尽可能的使用NOT NULL6>. 固定长度的表会更快7>. 拆分大的DELETE 或INSERT 语句8>. 查询的列越小越快有些where条件会导致索引无效:Ø where子句的查询条件里有!=,MySQL将无法使用索引。Ø where子句使用了Mysql函数的时候,索引将无效Ø 使用LIKE进行搜索匹配的时候,模糊匹配不能放在前面,否则失效。如%xxxx配置优化MySQL服务器全局参数优化分表(横、纵)减少单表的数据量及将常用列和不常用列、大列和小列分到不同的表。4. 你做的三个项目里应该都会用到权限设计,你对表是怎么设计的?按照RBAC权限体系设计通用的权限管理表5. 你们对表的设计怎么优化?你觉得一张表装多少行数据才会影响性能?数据类型:数字类型尽量不选择double、float,尽量使用decimal、int和long类型。字符类型除非非得是TEXT,而要尽量使用CHAR和VARCHAR。日期时间类型尽量使用TIMESTAMP,对于精确到某天的日期类型尽量选择DATE。尽量不使用BLOB/CLOB等LOB类型。适当拆分:纵向分表适度冗余:空间换时间,将常用的需要连接查询的数据放到主表。不过,冗余的同时需要确保数据的一致性不会遭到破坏,确保更新的同时冗余字段也被更新。避免NULL:NULL 类型比较特殊,SQL 难优化。虽然 MySQL NULL类型和 Oracle 的NULL 有差异,会进入索引中,但如果是一个组合索引,那么这个NULL 类型的字段会极大影响整个索引的效率。此外,NULL 在索引中的处理也是特殊的,也会占用额外的存放空间。Mysql单表如果数据结构简单2000W以下几乎可以支撑,如果复杂的数据结构500W既可以考虑分表,一般而言如果单表超过5000W,那么性能下降比较厉害。6. 数据库最基本,最常用的优化是什么?表结构优化:正确的数据类型选择、横向/纵向分表、建立索引、删除不必要的字段、适度冗余索引优化:主键索引、独立索引、联合索引SQL语句优化:尽量使用索引、尽量不对条件左边的对象进行运算(包括函数运算)、尽量不使用(!= / <> / not / or)等,可用union代替between and 区间的取值、尽量使用exists代替in、使用like时尽量使用左匹配key%、一般表连接比子查询更快存储过程:利用存储过程完成复杂且传输数据量大的逻辑。7. 数据库储存引擎myisam / innodb的区别MyISAM不支持事务,而InnoDB支持InnoDB支持数据行锁定,MyISAM不支持行锁定,只支持锁定整个表InnoDB支持外键,MyISAM不支持InnoDB的主键范围更大,最大是MyISAM的2倍。InnoDB不支持全文索引和GIS数据,而MyISAM支持。MyISAM磁盘上是3个文件,.frm文件存储表定义。数据文件的扩展名为.MYD (MYData)。索引文件的扩展名是.MYI (MYIndex)。InnoDB:所有的表都保存在同一个数据文件中(也可能是多个文件,或者是独立的表空间文件),InnoDB表的大小只受限于操作系统文件的大小,一般为2GB。MyISAM:可被压缩,存储空间较小。支持三种不同的存储格式:静态表(默认,但是注意数据末尾不能有空格,会被去掉)、动态表、压缩表。InnoDB:需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。8. 模糊查询可以使用索引吗?可以,但必须是左匹配key%9. 索引的优缺点优点:加快查询效率和表连接的效率、减少分组和排序时间。缺点:创建和更新索引需要耗费时间,随着数据量的增加而增加。索引会额外占用磁盘存储空间。9 java中4种修饰符分别为public、protect、default、private 的区别修饰符同类同包子类公共private(私有)默认不写protected(受保护)public(公共) 主要是修饰类中的成员(字段、方法、构造方法,内部类); public 默认不写: 可以修饰类 private protedted: 不能够修饰类(外部类)10 介绍一下Hibernate的缓存机制(或者问:二级缓存)Hibernate中的缓存分一级缓存和二级缓存。 一级缓存就是Session级别的缓存,在事务范围内有效是,内置的不能被卸载。二级缓存是SesionFactory级别的缓存,从应用启动到应用结束有效。是可选的,默认没有二级缓存,需要手动开启。 保存数据库后,在内存中保存一份,如果更新了数据库就要同步更新。 什么样的数据适合存放到第二级缓存中? 1)很少被修改的数据 帖子的最后回复时间2)经常被查询的数据 电商的地点2) 不是很重要的数据,允许出现偶尔并发的数据 3) 不会被并发访问的数据 4) 常量数据 扩展:hibernate的二级缓存默认是不支持分布式缓存的。使用memcahe,redis等中央缓存来代替二级缓存。11 说说你日常用到存储过程与触发器的场景触发器:实施复杂的安全性检查(例如:禁止在非工作时间插入新员工数据)数据确认或审计(例如:涨薪水,涨后的薪水不能小于涨前)数据备份与同步(给更新员工信息后自动备份新信息到备份表,或更新和员工相关连的冗余信息)存储过程:定时性的ETL任务、报表统计函数及复杂业务(大量SQL及大数据量传输)可以采用存储过程处理,另外涉及到算法或数据保密的情况也可以将保密逻辑及数据放到存储过程中计算完成,程序只关注传入参数及返回结果。12 String , StringBuffer,StringBuilder的区别String(JDK1.0时代) 不可变字符序列StringBuffer(JDK1.0时代) 线程安全的可变字符序列StringBuilder(JDK1.5时代) 非线程安全的可变字符序列 String和StringBuffer中的value都用于存储字符序列,String中的是常量(final)数组,只能被赋值一次。 StringBuffer中的value就是一个很普通的数组,而且可以通过append()方法将新字符串加入value末尾。StringBuffer线程安全,而StringBuilder不是。StringBuilder的效率比StringBuffer稍高,如果不考虑线程安全,StringBuilder应该是首选。StringBuffer对象的append效率要高于String对象的"+"连接操作。13 int与Integer的区别int 是基本数据类型,Integer是其包装类,注意是一个类。Integer默认值是null,而int默认值是0;声明为Integer的变量需要实例化,而声明为int的变量不需要实例化;Integer是对象,用一个引用指向这个对象,而int是基本类型,直接存储数值。14 如何实现序列化,有什么意义,适用于那些场景?(追问:序列化接口在JVM是怎么实现的)序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决对象流读写操作时可能引发的问题(如果不进行序列化可能会存在数据乱序的问题)。 要实现序列化,需要让一个类实现Serializable接口,该接口是一个标识性接口,标注该类对象是可被序列化的,然后使用一个输出流来构造一个对象输出流并通过writeObject(Object)方法就可以将实现对象写出(即保存其状态);如果需要反序列化则可以用一个输入流建立对象输入流,然后通过readObject方法从流中读取对象。序列化除了能够实现对象的持久化之外,还能够用于对象的深度克隆。只有实现了 serializable和Externalizable接口的类的对象才能被序列化 后者是前者的子类 实现这个借口的类完全由自身来控制序列化的行为,而仅仅实现前者的类可以采用默认的序列化方式。实现这两个接口 标志着对象可以被序列化了Java 串行化技术可以使你将一个对象的状态写入一个Byte 流里,并且可以从其它地方把该Byte 流里的数据读出来,重新构造一个相同的对象。这种机制允许你将对象通过网络进行传播,并可以随时把对象持久化到数据库、文件等系统里。Java的串行化机制是RMI、EJB等技术的技术基础。用途:利用对象的串行化实现保存应用程序的当前工作状态,下次再启动的时候将自动地恢复到上次执行的状态。15 JDBC连接数据库的步骤加载数据库驱动 Class.forName("com.mysql.jdbc.Driver") ; 创建数据库连接 Connection con = DriverManager.getConnection(url , username , password ) ;创建一个Statement 1、执行静态SQL语句。通常通过Statement实例实现。 2、执行动态SQL语句。通常通过PreparedStatement实例实现。 3、执行数据库存储过程。通常通过CallableStatement实例实现。执行SQL语句 Statement接口提供了三种执行SQL语句的方法:executeQuery 、executeUpdate和execute方法。处理结果ResultSet关闭JDBC对象 关闭记录集ResultSet、声明Statement和连接Connection16 Mybatis中 #.和 $.的区别#语法,MyBatis会产生PreparedStatement语句中,并且安全的设置PreparedStatement参数,这个过程中MyBatis会进行必要的安全检查和转义。$是直接输出变量的值,未经过预编译的,仅仅是取变量的值,是非安全的,存在sql注入.尽量使用#,但是$在什么情况下使用呢?有时候可能需要直接插入一个不做任何修改的字符串到SQL语句中。这时候应该使用$语法。比如,动态SQL中的字段名,如:ORDER BY $columnName17 什么是乐观锁,什么是悲观锁,两者的区别是什么悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。开始改变对象时锁住直到完成所有操作后才释放。乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。修改过程不锁定对象,直到提交所做更改时才将对象锁住。读取时不加锁,因此可能会造成脏读。乐观锁的实现方式使用自增长的整数表示数据版本号。更新时检查版本号是否一致,比如数据库中数据版本为6,更新提交时version=6+1,使用该version值(=7)与数据库version+1(=7)作比较,如果相等,则可以更新,如果不等则有可能其他程序已更新该记录,所以返回错误。使用时间戳来实现.注:对于以上两种方式,Hibernate自带实现方式:在使用乐观锁的字段前加annotation: Version, Hibernate在更新时自动校验该字段。在实际生产环境里边,如果并发量不大且不允许脏读,可以使用悲观锁解决并发问题;但如果系统的并发非常大的话,悲观锁定会带来非常大的性能问题,所以我们就要选择乐观锁定的方法.18 Vector ArrayList LinkedList的区别这三者都实现了List 接口.所有使用方式也很相似,主要区别在于因为实现方式的不同,所以对不同的操作具有不同的效率。ArrayList 是一个可改变大小的数组.当更多的元素加入到ArrayList中时,其大小将会动态地增长.内部的元素可以直接通过get与set方法进行访问,因为ArrayList本质上就是一个数组.LinkedList 是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList.当然,这些对比都是指数据量很大或者操作很频繁的情况下的对比,如果数据和运算量很小,那么对比将失去意义.Vector 和ArrayList类似,但属于强同步类。如果你的程序本身是线程安全的(thread-safe,没有在多个线程之间共享同一个集合/对象),那么使用ArrayList是更好的选择。Vector和ArrayList在更多元素添加进来时会请求更大的空间。Vector每次请求其大小的双倍空间,而ArrayList每次对size增长50%.而 LinkedList 还实现了 Queue 接口,该接口比List提供了更多的方法,包括 offer(),peek(),poll()等.注意: 默认情况下ArrayList的初始容量非常小,所以如果可以预估数据量的话,分配一个较大的初始值属于最佳实践,这样可以减少调整大小的开销。19 Hashtable HashMap TreeMap的区别 Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用Collections的synchronizedMap方法使HashMap具有同步的能力. Hashtable 与 HashMap类似,但是主要有6点不同。 1.HashTable的方法是同步的,HashMap未经同步,所以在多线程场合要手动同步HashMap这个区别就像Vector和ArrayList一样。 2.HashTable不允许null值,key和value都不可以,HashMap允许null值,key和value都可以。HashMap允许key值只能由一个null值,因为hashmap如果key值相同,新的key,