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

关于项目经验

关于专业技能
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)
当然这只是最基本的,出乎意料地,几次面试几乎都被同时问到了一个问题,问法不尽相同,总结起来是这么一个意思:
问题:
假如有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、个人未来的发展方向

  • 11
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java后端开发工程师需要掌握以下基本技能: 1. Java编程语言:熟练掌握Java编程语言的基本语法、面向对象编程思想和常用的类库。 2. 数据库管理:熟悉关系型数据库(如MySQL、Oracle)和NoSQL数据库(如MongoDB、Redis)的使用和管理,具备SQL语言的编写和优化能力。 3. Web开发框架:熟悉常用的Java Web开发框架,例如Spring、Spring MVC和Spring Boot等,能够进行Web应用的开发和调试。 4. 分布式系统:了解分布式系统的基本原理和常用技术,如分布式缓存、消息队列、分布式文件系统等,能够进行分布式系统的设计和开发。 5. 微服务架构:熟悉微服务架构的设计理念和实践,具备使用Spring Cloud等微服务框架进行开发和管理的能力。 6. 接口设计与开发:能够设计和开发符合RESTful风格的接口,熟悉HTTP协议和常用的接口调试工具。 7. 单元测试与集成测试:具备编写单元测试和集成测试的能力,并了解常用的测试框架和工具,如JUnit、Mockito等。 8. 版本控制工具:熟练使用Git等版本控制工具进行代码管理和协作开发。 9. 性能优化与调优:具备对系统性能进行评估、优化和调优的能力,了解常用的性能监测和调优工具。 10. 问题排查与调试:具备快速定位和解决问题的能力,熟悉常见的调试工具和技巧。 11. Linux基础:熟悉Linux操作系统的基本使用和常用命令,能够进行基本的系统配置和维护。 以上是Java后端开发工程师应该掌握的基本技能,通过不断学习和实践,不断提升自己的技术水平和能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值