大家好,又见面了,我是你们的朋友全栈君。
关于项目经验
关于专业技能 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) {
代码语言:javascript复制 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的实现原理:
代码语言:javascript复制 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、个人未来的发展方向
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/190176.html原文链接:https://javaforall.cn