地点:大连科技创新城,没有人。。。就像以前的软件园。。
时间:面试安排为2点半,因为怕迟到下课就去,结果到那才1点半,面试到2点50。
人物:两个人,据估计一个是项目经理,一个是技术总监(博士生)。然后是HR姐姐(27岁,实习后,在这个公司待了4,5年)给我介绍公司情况,以及填写我的相关信息。
事件:
面试开始,首先是自我介绍,同样的介绍个人信息,项目经验,在技术上的特长,最后是获得的奖项。
然后开始提问,
项目经理
1.最近做了哪个项目介绍一下;
2.spring的优缺点;
主要由七个模块组成,其中Spring AOP采用了面向切面编程的思想,使Spring框架管理的对象支持AOP,同时这个模块也提供了事务管理,可以不依赖EJB组件,就可以将事务管理集成到应用程序中;然后Spring MVC提供了一个构建Web应用程序的MVC的实现。
框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。
引申
什么是面向切面编程:最常见的就是日志记录了,举个例子,我们现在提供一个查询学生信息的服务,但是我们希望记录有谁进行了这个查询。如果按照传统的OOP的实现的话,那我们实现了一个查询学生信息的服务接口(StudentInfoService)和其实现 类 (StudentInfoServiceImpl.java),同时为了要进行记录的话,那我们在实现类(StudentInfoServiceImpl.java)中要添加其实现记录的过程。这样的话,假如我们要实现的服务有多个呢?那就要在每个实现的类都添加这些记录过程。这样做的话就会有点繁琐,而且每个实现类都与记录服务日志的行为紧耦合,违反了面向对象的规则。那么怎样才能把记录服务的行为与业务处理过程中分离出来呢?看起来好像就是查询学生的服务自己在进行,但却是背后日志记录对这些行为进行记录,并且查询学生的服务不知道存在这些记录过程,这就是我们要讨论AOP的目的所在。AOP的编程,好像就是把我们在某个方面的功能提出来与一批对象进行隔离,这样与一批对象之间降低了耦合性,可以就某个功能进行编程。
什么是EJB:把你编写的软件中那些需要执行制定的任务的类,不放到客户端软件上了,而是给他打成包放到一个服务器上了。
3.hibernate的优缺点;
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。
缺点:
一、由于对持久层封装过于完整,导致开发人员无法对SQL进行优化,无法灵活使用JDBC的原生SQL,Hibernate封装了JDBC,所以没有JDBC直接访问数据库效率高。要使用数据库的特定优化机制的时候,不适合用Hibernate 二、框架中使用ORM原则,导致配置过于复杂,一旦遇到大型项目,比如300张表以上,配置文件和内容是非常庞大的,另外,DTO满天飞,性能和维护问题随之而来 三、如果项目中各个表中关系复杂,表之间的关系很多,在很多地方把lazy都设置false,会导致数据查询和加载很慢,尤其是级联查询的时候。 四、Hibernate在批量数据处理时有弱势,对于批量的修改,删除,不适合用Hibernate,这也是ORM框架的弱点
4.他们的作用。
同上。
技术总监
1.除去框架,对于数据库,Java,Java Web等这些基础你还剩多少。(这个比较关键,值得我警醒!)
2.ArrayList和linklist区别,什么时候用ArrayList什么时候用linklist;(即数组和链表的优缺点)
3.对于String,String Buffer这些了解多少;
4.排序的比较,什么时候用冒泡,什么时候用快排;
http://blog.youkuaiyun.com/xiazdong/article/details/8462393
5.对于继承,接口方面的理解,比如dao层使用了继承,如果两个人同时访问,是否有锁,是否考虑了并发性!(这个是我之前从来没有考虑过得,并发,用户量大的情况)
6.Struts-Spring-Hibernate,他们的特点!(几乎场场面试都面!!!)
7.ArrayList初始值为多少;
ArrayList的列表对象实质上是存储在一个引用型数组里的,有人认为该数组有“自动增长机制”可以自动改变size大小。正式地说,该数组是无法改变
大小的,实际上它只是改变了该引用型数组的指向而已。下面,让我们来看看java是怎样实现ArrayList类的。
一、ArrayList类的实质
ArrayList底层采用Object类型的数组实现,当使用不带参数的构造方法生成ArrayList对象时,
实际上会在底层生成一个长度为
10
的Object类型数组。
首先,ArrayList定义了一个私有的未被序列化的数组elementData,用来存储ArrayList的对象列表(注意只定义未初始):
private
transient
Object[] elementData;
其次,以指定初始容量(Capacity)或把指定的Collection转换为引用型数组后实例化elementData数组;如果没有指定,则预置初始容量为
10
进行
实例化。把私有数组预先实例化,然后通过copyOf方法覆盖原数组,是实现自动改变ArrayList的大小(size)的关键。有人说ArrayList是复杂的数组,我
认为不如说ArrayList是关于数组的系统的方法组合。
ArrayList的构造方法源码如下:
// 用指定的初始容量构造一个空列表。
public
ArrayList(
int
initialCapacity) {
super
();
if
(initialCapacity <
0
)
throw
new
IllegalArgumentException(
"Illegal Capacity: "
+initialCapacity);
this
.elementData =
new
Object[initialCapacity];
//属性指向<a href="https://www.baidu.com/s?wd=%E6%96%B0%E5%BB%BA&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3uHbYnjD4n16LPhPhnv7-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6K1TL0qnfK1TL0z5HD0IgF_5y9YIZ0lQzqlpA-bmyt8mh7GuZR8mvqVQL7dugPYpyq8Q1D1PHmvP1TzP1b4rjczPj0sPf" target="_blank" class="baidu-highlight">新建</a>长度为初始容量的临时数组
}
// 使用初始容量10构造一个空列表
public
ArrayList() {
this
(
10
);
}
/ *构造包含利用collection的迭代器按顺序返回的指定collection元素的列表
*
@param
c 集合,它的元素被用来放入列表t
*
@throws
NullPointerException 如果指定集合为
null
*/
public
ArrayList(Collection<?
extends
E> c) {
elementData = c.toArray();
//用Collection初始化数组elementData
size = elementData.length;
if
(elementData.getClass() != Object[].
class
)
elementData = Arrays.copyOf(elementData, size, Object[].
class
);
}
二、ArrayList实现自动改变size机制
为了实现这一机制,java引进了Capacity和size概念,以区别数组的length。为了保证用户增加新的列表对象,java设置了最小容量(minCapacity)
,通常情况上,它大于列表对象的数目,所以Capactiy虽然就是底层数组的长度(length),但是对于最终用户来讲,它是无意义的。而size存储着列表
对象的数量,才是最终用户所需要的。为了防止用户错误修改,这一属性被设置为privae的,不过可以通过size()获取。
下面,对ArrayList的初始以及其列表对象的增加和删除等三种情况下的size自动改变机制进行分析。
1
、初始Capacity和size值。
从上面给出的ArrayList构造方法源码中,我们不难看出Capacity初始值(initialCapacity)可以由用户直接指定或由用户指定的Collection集合存
储的对象数目确定,如果没有指定,系统默认为
10
。而size的被声明为
int
型变量,默认为
0
,当用户指定Collection创建ArrayList时,size值等于
initialCapacity。
2
、add()方法
该方法的源码如下:
public
boolean
add(E e) {
ensureCapacityInternal(size +
1
);
elementData[size++] = e;
//添加对象时,自增size
return
true
;
}
方法中调用的ensureCapacityInternal主要用来调整容量,修改elementData数组的指向。其中涉及到
3
个方法的调用,其核心在于grow方法:
private
void
ensureCapacityInternal(
int
minCapacity) {
modCount++;
//定义于ArrayList的父类AbstractList,用于存储结构修改次数
// overflow-conscious code
if
(minCapacity - elementData.length >
0
)
grow(minCapacity);
}
private
void
grow(
int
minCapacity) {
// overflow-conscious code
int
oldCapacity = elementData.length;
int
newCapacity = oldCapacity + (oldCapacity >>
1
);
//新容量扩大到原容量的1.5倍,右移一位相关于原数值除以2。
if
(newCapacity - minCapacity <
0
)
newCapacity = minCapacity;
if
(newCapacity - MAX_ARRAY_SIZE >
0
)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
private
static
int
hugeCapacity(
int
minCapacity) {
if
(minCapacity <
0
)
// overflow
throw
new
OutOfMemoryError();
return
(minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
//MAX_ARRAY_SIZE和Integer.MAX_VALUE为常量,详细请参阅下面的注解
}
通过以上代码,我们可知java自动增加ArrayList大小的思路是:向ArrayList添加对象时,原对象数目加
1
如果大于原底层数组长度,则以适当长度新
建一个原数组的拷贝,并修改原数组,指向这个<a href=
"https://www.baidu.com/s?wd=%E6%96%B0%E5%BB%BA&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3uHbYnjD4n16LPhPhnv7-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6K1TL0qnfK1TL0z5HD0IgF_5y9YIZ0lQzqlpA-bmyt8mh7GuZR8mvqVQL7dugPYpyq8Q1D1PHmvP1TzP1b4rjczPj0sPf"
target=
"_blank"
class
=
"baidu-highlight"
>新建</a>数组。原数组自动抛弃(java垃圾回收机制会自动回收)。size则在向数组添加对象,自增
1
。
注解:
//定义于该类的常量,用来分配数组的size最大值。一些 <a href="https://www.baidu.com/s?wd=VM&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3uHbYnjD4n16LPhPhnv7-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6K1TL0qnfK1TL0z5HD0IgF_5y9YIZ0lQzqlpA-bmyt8mh7GuZR8mvqVQL7dugPYpyq8Q1D1PHmvP1TzP1b4rjczPj0sPf" target="_blank" class="baidu-highlight">VM</a>s在数组里保留字头,试图分配更大数组时可能导致OutOfMemoryError:被请求数组的
size超出<a href=
"https://www.baidu.com/s?wd=VM&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1Y3uHbYnjD4n16LPhPhnv7-0ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6K1TL0qnfK1TL0z5HD0IgF_5y9YIZ0lQzqlpA-bmyt8mh7GuZR8mvqVQL7dugPYpyq8Q1D1PHmvP1TzP1b4rjczPj0sPf"
target=
"_blank"
class
=
"baidu-highlight"
>VM</a>界限。
private
static
final
int
MAX_ARRAY_SIZE = Integer.MAX_VALUE -
8
;
//在java.lang.Integer类中常量MIN_VALUE、MAX_VALUE如下:
public
static
final
int
MIN_VALUE =
0x80000000
;
//整型取值区间下界:-2147483648
public
static
final
int
MAX_VALUE =
0x7fffffff
;
//整型取值区间上界:2147483647
//在java.util.AbstractList中modCount定义如下:
protected
transient
int
modCount =
0
;
3
、remove()方法
该重构方法其一源码如下(其它的就不累述了):
public
E remove(
int
index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int
numMoved = size - index -
1
;
if
(numMoved >
0
)
System.arraycopy(elementData, index+
1
, elementData, index,
numMoved);
//将后面的列表对象前移
elementData[--size] =
null
;
// 数组前移一位,size自减,空出来的位置置null,具体的对象的销毁由Junk收集器负责
return
oldValue;
}
private
void
rangeCheck(
int
index) {
//边界检查
if
(index <
0
|| index >=
this
.size)
throw
new
IndexOutOfBoundsException(outOfBoundsMsg(index));
}
E elementData(
int
index) {
//获取指定index所在位置的对象
return
(E) elementData[index];
}
通过remove()源码的学习,我们不难看出,其改变ArrayList大小的核心与add()方法相似,都是同数组拷贝。
另外,如果确有必要,用户也可以指定ArrayList实例的容量,可以有效的降低时间成本。它是通过调用ensureCapacityInternal来实现的,源代码
如下:
public
void
ensureCapacity(
int
minCapacity) {
if
(minCapacity >
0
)
ensureCapacityInternal(minCapacity);
}
因为size为
private
的,java给出方法来访问它:
public
int
size() {
checkForComodification();
return
this
.size;
}
综上所述,在用户向ArrayList追加对象时,Java总是要先计算容量(Capacity)是否适当,若容量不足则把原数组拷贝到以指定容量为长度创建的
新数组内,并对原数组变量重新赋值,指向新数组。在这同时,size进行自增
1
。在删除对象时,先使用拷贝方法把指定index后面的对象前移
1
位(如果
有的话),然后把空出来的位置置
null
,交给Junk收集器销毁,size自减
1
,即完成了。
HR
1.住哪,今后的打算;
2.这几年的打算;
3.介绍公司概况;
4.介绍福利:餐补15,车补10,五险一金,无请假,如果有加班,用加班的工时代替请假,无加班费;
面试总结:公司路途遥远,没有加班费,我开出6k的工资,他们还是比较难接受。但是面试获得的比较多,需要考虑考虑自己在基础方面的理解,该背的东西还是要背,面试问的东西基本大同小异,对于,接口/List/Spring/Hibernate/排序/继承/并发这几个地方需要着重考虑!!!