您的位置:首页 > 编程语言 > Java开发

三年Java软件工程师应该掌握的技能

2016-04-18 10:31 337 查看
关于项目经验

关于专业技能

1、基本语法

static、final、transient等关键字的作用

foreach循环的原理等等

static:

1.静态变量

2.静态方法

3.静态代码块

final:

1.修饰类的属性,作用:修饰静态变量不可变,不建议修饰实例变量

2.修饰类的方法,作用:可以被继承,但不能重写

3.修饰类,作用:类不可以被继承

transient:

1.一旦变量被transient修饰,变量将不再是对象持久化(序列化)的一部分,该变量内容在序列化后没有值。

2.transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。

3.被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。

serialVersionUID的作用:

如果没有明确指定serialVersionUID,序列化的时候会根据字段和特定的算法生成一个serialVersionUID,当属性有变化时这个id发生了变化,所以反序列化的时候

就会失败。抛出“本地classd的唯一id和流中class的唯一id不匹配”。

2.集合

List、Map、Set,问的是各种实现类的底层实现原理,实现类的优缺点。

集合要掌握的是ArrayList、LinkedList、Hashtable、HashMap、ConcurrentHashMap、HashSet的实现原理,

能流利作答,当然能掌握CopyOnWrite容器和Queue是再好不过的

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

Hashtable继承Map接口,Hashtable是同步的。实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为key或者value。

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

HashMap解析:http://zhangshixi.iteye.com/blog/672697

ArrayList解析:http://www.cnblogs.com/ITtangtang/p/3948555.html

ArrayList源码中:private transient E[] elementData; //属性存放数据

ArrayList是会开辟多余空间来保存数据的,而系列化和反序列化这些没有存放数据的空间是要消耗更多资源的,

所以ArrayList的数组就声明为transient,自己实现write/readObject方法,仅仅系列化已经存放的数据。

ConcurrentHashMap的问题在面试中问得特别多

ConcurrentHashMap与HashTable的区别主要是锁的粒度不同,HashTable当写数据时,锁住整个Hash表,而ConcurrentHashMap是所Hash表的段(桶)

(1)ConcurrentHashMap的锁分段技术

答:ConcurrentHashMap将Hash表分成多个段(默认16个段),则有更新数据时,大部分是锁段,不锁整张Hash表,提高了性能

每个segment则是一个传统意义上的hashtable

(2)ConcurrentHashMap的读是否要加锁,为什么

答:读大部分情况下不加锁。当在get的时候,经过Hash,找到Hash表中的段(桶),再找到key在该段对应的index值,后会进行遍历数据,详见代码readValueUnderLock():

在判断存在hash值的节点,且key也存在,而值为null,则需要重新上锁再读。

这里当v为空时,可能是一个线程正在改变节点,而之前的get操作都未进行锁定,根据bernstein条件,读后写或写后读都会引起数据的不一致,

所以这里要对这个e重新上锁再读一遍,以保证得到的是正确值

V get(Object key, int hash) {

if (count != 0) { // read-volatile

HashEntry e = getFirst(hash);

while (e != null) {

if (e.hash == hash && key.equals(e.key)) {

V v = e.value;

if (v != null)

return v;

return readValueUnderLock(e); // recheck

}

e = e.next;

}

}

return null;

}

V readValueUnderLock(HashEntry e) {

lock();

try {

return e.value;

} finally {

unlock();

}

}

(3)ConcurrentHashMap的迭代器是强一致性的迭代器还是弱一致性的迭代器

答:弱一致性的迭代器

public static void main(String[] args) {

Map<String, String> testMap = new ConcurrentHashMap<String, String>();

testMap.put("pengjie1", "pengjie test 1");
testMap.put("pengjie2", "pengjie test 2");
testMap.put("pengjie3", "pengjie test 3");
testMap.put("pengjie4", "pengjie test 4");
testMap.put("pengjie5", "pengjie test 5");
testMap.put("pengjie6", "pengjie test 6");
testMap.put("pengjie7", "pengjie test 7");

Collection<String> values  = testMap.values();

Iterator<String> iterator = values.iterator();

while (iterator.hasNext()) {
String name = (String) iterator.next();
System.out.println("name :"+name);

testMap.remove("pengjie1");//pengjie1被删除,但不影响执行
}
System.out.print("Map size:"+testMap.size());
}


结果:

name :pengjie test 7

name :pengjie test 2

name :pengjie test 5

name :pengjie test 3

name :pengjie test 6

name :pengjie test 4

Map size:6

3、设计模式

http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html

简单工厂模式、静态工厂方法模式、抽象工厂模式、单例模式、装饰模式、代理模式、观察者模式

面试中关于设计模式的问答主要是三个方向:

(1)你的项目中用到了哪些设计模式,如何使用

(2)知道常用设计模式的优缺点

(3)能画出常用设计模式的UML图

装饰模式:顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例

代理模式:就是多一个代理类出来,替原对象进行一些操作,比如我们在租房子的时候回去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做

装饰模式与代理模式的区别:装饰模式持有对被装饰对象的实例,而代理模式没有。

装饰模式是对被装饰对象的增强。代理模式是对被代理类的限制

当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。

当我们使用装饰器模式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。

4、多线程

这也是必问的一块了。因为三年工作经验,所以基本上不会再问你怎么实现多线程了,

会问得深入一些比如说Thread和Runnable的区别和联系、多次start一个线程会怎么样、线程有哪些状态。

(一个Thread的实例一旦调用start()方法,这个实例的started标记就标记为true)

当然这只是最基本的,出乎意料地,几次面试几乎都被同时问到了一个问题,问法不尽相同,总结起来是这么一个意思:

问题:

4000

假如有Thread1、Thread2、Thread3、Thread4四条线程分别统计C、D、E、F四个盘的大小,

所有线程都统计完毕交给Thread5线程去做汇总,应当如何实现?

5、JDK源码

要想拿高工资,JDK源码不可不读。上面的内容可能还和具体场景联系起来,JDK源码就是实打实地看你平时是不是爱钻研了。

LZ面试过程中被问了不少JDK源码的问题,其中最刁钻的一个问了LZ,String的hashCode()方法是怎么实现的,幸好LZ平时String源代码看得多,

答了个大概。JDK源码其实没什么好总结的,纯粹看个人,总结一下比较重要的源码:

(1)List、Map、Set实现类的源代码

(2)ReentrantLock、AQS的源代码

(3)AtomicInteger的实现原理,主要能说清楚CAS机制并且AtomicInteger是如何利用CAS机制实现的

(4)线程池的实现原理

(5)Object类中的方法以及每个方法的作用

这些其实要求蛮高的,LZ去年一整年基本把JDK中重要类的源代码研究了个遍,真的花费时间、花费精力,当然回头看,是值得的—-不仅仅是为了应付面试。

AtomicInteger的实现原理:

private volatile int value;//取内存中的最新值

public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
//关键函数,将current与内存中的值进行比较,若相同,则更新,并返回true;
//若内存中的值已经被修改,则返回false,进入下一次循环
if (compareAndSet(current, next))
return next;
}
}


多线程分析:

在使用中我们一般使用Executors类的静态方法来创建线程池,除非我们对于线程池非常理解才能自己去灵活的规划线程池类(可以用来继承ThreadPoolExecutor)

1:核心线程:简单来讲就是线程池中能否允许同时并发运行的线程的数量

2:线程池大小:线程池中最多能够容纳的线程的数量。

3:队列:对提交过来的任务的处理模式。

如果队列发过来的任务,发现线程池中正在运行的线程的数量小于核心线程,则立即创建新的线程,无需进入队列等待。

如果正在运行的线程等于或者大于核心线程,则必须参考提交的任务能否加入队列中去

任务进入队列总共只有三种情况:

1.能加入,且队列无界,则最多运行核心线程池数 ,最大线程池数没有作用

2.能加入,且队列有界,则队列满后,创新新的线程运行任务,超过最大线程池数后拒绝任务

3.不能加入,直接提交到线程池。创建新的线程运行任务,超过最大线程池数后拒绝任务

参考多线程分析:http://my.oschina.net/u/1398304/blog/376827

队列的三种策略:

SynchronousQueue 直接提交,也就是上面讲到的所有任务不进入队列去等待。此时小于核心线程就增加,多于或等于核心线程数时,还是增加线程,最大为线程池中的最大允许。超出就拒绝。

LinkedBlockingQueue 无界队列 此时超过核心线程后的任务全部加入队列等待,系统最多只能运行核心线程数量的线程。这种方法相当于控制了并发的线程数量。

ArrayBlockingQueue 有界队列 此时超过核心线程后的任务先加入队列等待,超出队列范围后的任务就生成线程,但创建的线程最多不超过线程池的最大允许值。

1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。

2、当调用 execute() 方法添加一个任务时,线程池会做如下判断:

a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;

b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。

c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;

d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。

3、当一个线程完成任务时,它会从队列中取下一个任务来执行。

4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

这个过程说明,并不是先加入任务就一定会先执行。假设队列大小为 4,corePoolSize为2,maximumPoolSize为6,

那么当加入15个任务时,执行的顺序类似这样:首先执行任务 1、2,然后任务3~6被放入队列。

这时候队列满了,任务7、8、9、10 会被马上执行,而任务 11~15 则会抛出异常。

最终顺序是:1、2、7、8、9、10、3、4、5、6。当然这个过程是针对指定大小的ArrayBlockingQueue来说,

如果是LinkedBlockingQueue,因为该队列无大小限制,所以不存在上述问题。

6、框架

老生常谈,面试必问的东西。一般来说会问你一下你们项目中使用的框架,然后给你一些场景问你用框架怎么做,

比如我想要在Spring初始化bean的时候做一些事情该怎么做、想要在bean销毁的时候做一些事情该怎么做、MyBatis中$和#的区别等等,这些都比较实际了,平时积累得好、有多学习框架的使用细节自然都不成问题。

如果上面你的问题答得好,面试官往往会深入地问一些框架的实现原理。

问得最多的就是Spring AOP的实现原理,当然这个很简单啦,两句话就搞定的的事儿,即使你不会准备一下就好了。

LZ遇到的最变态的是让LZ画一下Spring的Bean工厂实现的UML图,当然面对这样一个有深度的问题,LZ是绝对答不出来的/(ㄒoㄒ)/~~

7、数据库

8、数据结构和算法分析

可以不了解它们的具体实现,但是要知道什么是二叉查找树、什么是平衡树,AVL树和红黑树的区别。

记得某次面试,某个面试官和我聊到了数据库的索引,他问我:

你知道索引使用的是哪种数据结构实现吗?

为什么要使用树吗?

9、Java虚拟机

出乎LZ的意料,Java虚拟机应该是很重要的一块内容,结果在这几家公司中被问到的概率几乎为0。

10、Web方面的一些问题

Java主要面向Web端,因此Web的一些问题也是必问的。LZ碰到过问得最多的两个问题是:

谈谈分布式Session的几种实现方式

常用的四种能答出来自然是让面试官非常满意的,另外一个常问的问题是:

讲一下Session和Cookie的区别和联系以及Session的实现原理

这两个问题之外,web.xml里面的内容是重点,Filter、Servlet、Listener,不说对它们的实现原理一清二楚吧,至少能对它们的使用知根知底。

另外,一些细节的方面比如get/post的区别、forward/重定向的区别、HTTPS的实现原理也都可能会被考察到。

关于HR面试

这轮的面试也必须重视起来,HR面试主要问的是几点:

1、简历中写的过去工作经历的离职原因

2、当前公司薪资待遇

3、期望能到怎样的一家公司

4、个人未来的发展方向
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 软件工程师