最近为公司面试了不少Java开发,有工作一两年的,也有工作十来年的人,在面试他人前,自己也需准备一下,免得错失人才,或者误导他人。为了更好的面试他人,所以我也会准备一番,全当查漏补缺(毕竟好东西我也不是很清楚的),因此,就最近面试情况及问题,进行汇总整理如下。
我一般面试提问,会从下面三个方面发问:
自我介绍
自我介绍,老生常谈的话题,大部分面试官都以此作为面试的开口,以了解面试者的基本信息(工作时间、工作经历)、做过哪些/哪类项目、会什么技术、擅长什么等。
温馨提示,个人自我介绍最好提前有所准备下,不至于说话磕磕碰碰,更重要的是要实事求是。自我介绍,也是对面试官产生第一印象开端,有了好的印象,才会有接下来的事情,对你后续面试及面试结果有一定的帮助。
技术、框架
技术及框架,在此进行分类整理(没有先后顺序),如下:
线程部分
1、使用过线程么?线程如何实现?
通过继承 Thread 类、实现Runnable 接口,在run方法中实现功能或业务逻辑。
2、线程中start和run方法有什么区别和联系?
调用start方法可启动线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,即:线程要执行的内容。
而run方法只是线程里面一个普通方法的调用而已,还是在主线程里执行。如果直接调用run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。
public static void main(String args[]) {
Thread t = new Thread() {
public void run() {
pong();
}
};
t.start();
System.out.print("ping");
}
public static void pong() {
System.out.print("pong");
}
输出结果: pingpong
public static void main(String args[]) {
Thread t = new Thread() {
public void run() {
pong();
}
};
t.run();
System.out.print("ping");
}
public static void pong() {
System.out.print("pong");
}
输出结果:pongping
通过以上两个程序实例,可以很容易的区分出start()方法和run()方法的区别:
3、了解过线程死锁么?如何有效的避免线程死锁?
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外界作用下,它们都将无法进行下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。
4、项目中有没有用过线程池 ?怎么用的 ?
使用过。我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题:如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。
通过使用线程池就可以解决这个问题,使得线程可以复用,就是执行完一个任务,并不被销毁,而是可以继续执行其他的任务。Java的线程池最核心是ThreadPoolExecutor类,线程池底层都是通过 ThreadPoolExecutor 来实现的:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
其中参数的意思分别为:
MyBatis 部分
1、mybatis 中$ 与 # 的区别?
都是可以来传递参数的,不过 # 可以方防止sql 注入,而 $ 就是字符串拼接的方式处理,可能会有sql 注入的问题。
#{} 在预处理时,会把参数部分用一个占位符 ? 代替 ,变成了如下的 sql 语句:
select * from user where name = ?;
而 ${} 则只是简单的字符串拼接,在动态解析阶段就直接拼接成了 最终的sql 语句:
select * from user where name = 'xcbeyond';
2、当实体类中的属性名和表中的字段名不一样 ,怎么办 ?
第1种: 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致。
<select id=”selectorder” parametertype=”int” resultetype=”me.gacl.domain.order”>
select order_id id, order_no orderno ,order_price price form orders where order_id=#{id};
</select>
第2种: 通过<resultMap>来映射字段名和实体类属性名的一一对应的关系。
<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<!–用id属性来映射主键字段–>
<id property=”id” column=”order_id”>
<!–用result属性来映射非主键字段,property为实体类属性名,column为数据表中的属性–>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>
3、MyBatis中怎么实现一个动态SQL?
Mybatis动态sql可以在Xml映射文件内,以标签的形式编写动态sql,执行原理是根据表达式的值 完成逻辑判断并动态拼接sql的功能。
Mybatis提供了9种动态sql标签:trim | where | set | foreach | if | choose | when | otherwise | bind。
4、Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?
不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;
原因就是namespace+id是作为Map<String, MapperStatement>的key使用的,如果没有namespace,就剩下id,那么,id重复会导致数据互相覆盖。有了namespace,自然id就可以重复,namespace不同,namespace+id自然也就不同。
更多详见Mybatis常见面试题总结
数据库
1、有没有使用过视图?什么场景下会考虑使用它?
视图,是一种虚拟的表,具有和一般表相同的功能。可以对视图进行增,改,查操作,试图是由一个表或者多个表的行或列的子集,即:是一个查询sql的查询结果集。
以下场景,一般会考虑使用视图:
2、有没有使用过索引?使用索引时有什么注意事项么?
表添加索引后,一定程度会加速表的查询速度,但过多的使用索引将会造成滥用。虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。
使用索引时的优缺点如下:
优点:
缺点:
3、查询语句速度很慢,如何优化?
可从以下几个方面进行优化:
其余内容逐步更新整理中,倘若有误、不足,欢迎大家留言吐槽、补充完善。