面试常见问题

之前为了面试总结的,不是很全,一些比较基础的就没有写下来,这里很多是可以作为加分项的吧。

Java的话这里有个比较全的总结:http://www.jianshu.com/p/b5f1121c3a2d

Java

基础

Java面向对象的基本特性?

  • 抽象:将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。
  • 继承:从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到信息的类被称为子类(派生类)。
  • 封装:把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。
  • 多态:允许不同子类的对象对同一消息做出不同的响应。

 

抽象类与接口的区别?

  • 抽象类需被子类继承;接口需被类实现
  • 抽象类中可以有普通变量;而接口中只能有静态常量
  • 抽象类中方法访问权限不限;接口中的方法都为public;
  • 抽象类中可以只方法声明,也可以做方法实现;接口中只能有方法声明(JDK8 中可以有静态方法和默认方法)
  • 抽象类只能单基础;接口可以多继承接口,也可以被实现多个接口

 

为什么内部类访问的局部变量必须被final修饰?

因为生命周期不同。局部变量在方法结束后就会被销毁,但内部类对象并不一定,这样就会导致内部类引用了一个不存在的变量。

所以编译器会在内部类中生成一个局部变量的拷贝,这个拷贝的生命周期和内部类对象相同,就不会出现上述问题。

但这样就导致了其中一个变量被修改,两个变量值可能不同的问题。为了解决这个问题,编译器就要求局部变量需要被final修饰,以保证两个变量值相同。

在JDK8之后,编译器不要求内部类访问的局部变量必须被final修饰,但局部变量值不能被修改(无论是方法中还是内部类中),否则会报编译错误。利用javap查看编译后的字节码可以发现,编译器已经加上了final。

源码:

字节码:

 

你了解哪些JDK1.8的新特性?

  • 接口的默认方法和静态方法
    JDK8允许我们给接口添加一个非抽象的方法实现,只需要使用default关键字即可,也可以定义被static修饰的静态方法
  • 对HashMap进行了改进,当单个桶的元素个数大于6时就会将实现改为红黑树实现,以避免构造重复的hashCode的攻击
  • JDK8拓宽了注解的应用场景,注解几乎可以使用在任何元素上,并且允许在同一个地方多次使用同一个注解
  • Lambda表达式

详细参考:http://blog.csdn.net/yczz/article/details/50896975

 

你知道哪些JDK中用到的设计模式?

  • 装饰模式:java.io
    java.io装饰模式
  • 单例模式:Runtime类
  • 简单工厂模式:Integer.valueOf方法
  • 享元模式:String常量池、Integer.valueOf(int i)、Character.valueOf(char c)
  • 迭代器模式:Iterator
  • 职责链模式:ClassLoader的双亲委派模型
  • 解释器模式:正则表达式java.util.regex.Pattern

详细参考:http://blog.csdn.net/gtuu0123/article/details/6114197

 

是否可以继承String类?

String类是final类故不可以继承,一切由final修饰过的都不能继承

 

String和StringBuffer、StringBuilder的区别

  • 可变性:
    String类中使用字符数组保存字符串,private final char value[],所以string对象是不可变的。
    StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。
  • 线程安全性:
    String中的对象是不可变的,也就可以理解为常量,线程安全。
    AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。
  • 性能:
    每次对String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer和StringBuilder每次都会对 对象本身进行操作,而不是生成新的对象并改变对象引用。

 

hashCode和equals方法的关系

equals为true,hashcode必相等;hashcode相等,equals可能不为true

 

什么是泛型、为什么要使用以及泛型擦除

泛型,即“参数化类型”。

创建集合时就指定集合元素的类型,该集合只能保存其指定类型的元素,避免使用强制类型转换。

Java编译器生成的字节码是不包涵泛型信息的,泛型类型信息将在编译处理是被擦除,这个过程即类型擦除。 泛型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。

类型擦除的主要过程如下:

  1. 将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
  2. 移除所有的类型参数。

 

Error、Exception区别

Error类和Exception类的父类都是throwable类,他们的区别是:

Error类一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。

Exception类表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

 

Unchecked Exception和Checked Exception,各列举几个

  • Unchecked Exception:
    • 指的是程序的瑕疵或逻辑错误,并且在运行时无法恢复。
    • 包括Error与RuntimeException及其子类,如:OutOfMemoryError, UndeclaredThrowableException, IllegalArgumentException, IllegalMonitorStateException, NullPointerException, IllegalStateException, IndexOutOfBoundsException等。
    • 语法上不需要声明抛出异常。
  • Checked Exception:
    • 代表程序不能直接控制的无效外界情况(如用户输入,数据库问题,网络异常,文件丢失等)
    • 除了Error和RuntimeException及其子类之外,如:ClassNotFoundException, NamingException, ervletException, SQLException, IOException等。
    • 需要try catch处理或throws声明抛出异常。

 

集合

Java集合类图

Java集合类图

 

HashMap和Hashtable区别

  • Hashtable的方法前面都有synchronized来同步,是线程安全的;HashMap未经同步,是非线程安全的。
  • Hashtable不允许null值(key和value都不可以) ;HashMap允许null值(key和value都可以)。
  • Hashtable有一个contains(Object value)功能和containsValue(Object value)功能一样。
  • Hashtable使用Enumeration进行遍历;HashMap使用Iterator进行遍历。
  • Hashtable中hash数组默认大小是11,增加的方式是 old*2+1;HashMap中hash数组的默认大小是16,而且一定是2的指数。
  • 哈希值的使用不同,Hashtable直接使用对象的hashCode; HashMap重新计算hash值,而且用与代替求模。

 

ArrayList和vector区别

  • Vector的方法前面都有synchronized来同步,是线程安全的;而ArrayList是非线程安全的。
  • List第一次创建的时候,会有一个初始大小,随着不断向List中增加元素,当 List 认为容量不够的时候就会进行扩容。Vector缺省情况下自动增长原来一倍的数组长度,ArrayList增长原来的50%。

 

Collection和Collections的区别

java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。

java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。

 

ConcurrentHashMap如何保证线程安全

JDK 1.7及以前:

ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。

详细参考:

http://www.cnblogs.com/ITtangtang/p/3948786.html

http://qifuguang.me/2015/09/10/[Java并发包学习八]深度剖析ConcurrentHashMap/

JDK 1.8:

Segment虽保留,但已经简化属性,仅仅是为了兼容旧版本。

插入时使用CAS算法:unsafe.compareAndSwapInt(this, valueOffset, expect, update)。 CAS(Compare And Swap)意思是如果valueOffset位置包含的值与expect值相同,则更新valueOffset位置的值为update,并返回true,否则不更新,返回false。插入时不允许key或value为null

与Java8的HashMap有相通之处,底层依然由“数组”+链表+红黑树;

底层结构存放的是TreeBin对象,而不是TreeNode对象;

CAS作为知名无锁算法,那ConcurrentHashMap就没用锁了么?当然不是,当hash值与链表的头结点相同还是会synchronized上锁,锁链表。

 

为什么HashMap不是线程安全

多线程同时put时,如果同时触发了rehash操作,会导致HashMap中的链表中出现循环节点,进而使得后面get的时候,会死循环。

 

虚拟机

引用的类型以及应用

http://zhangjunhd.blog.51cto.com/113473/53092

 

 

 

多线程

i++在多线程环境下是否存在问题,怎么解决?

虽然递增操作++i是一种紧凑的语法,使其看上去只是一个操作,但这个操作并非原子的,因而它并不会作为一个不可分割的操作来执行。实际上,它包含了三个独立的操作:读取count的值,将值加1,然后将计算结果写入count。这是一个“读取 - 修改 - 写入”的操作序列,并且其结果状态依赖于之前的状态。所以在多线程环境下存在问题。

要解决自增操作在多线程环境下线程不安全的问题,可以选择使用Java提供的原子类,如AtomicInteger或者使用synchronized同步方法。

 

多线程的实现方式

  • 继承Thread类,重写run()方法
  • 实现Runnable接口,重写run()方法
  • 使用ExecutorService、Callable、Future实现有返回结果的多线程

 

线程的状态

  • New (新生)
    如用new Thread()创建一个新线程,这个线程还没有开始运行
  • Runnable (可运行)
    一旦调用start方法,线程处于可运行状态。处于此状态的线程可能正在运行也可能没有运行,这取决于操作系统给线程提供运行的时间。
  • Blocked (被阻塞)
    当一个线程试图获取一个内部的对象锁,而该锁被其他线程持有,则该线程进入阻塞状态。当所有其他线程释放该锁,并且线程调度器允许本线程持有它的时候,该线程将变为非阻塞状态。
  • Waiting (等待)
    当线程等待另一个线程通知调度器一个条件时,进入等待状态,如调用Object.wait()方法时,需要等待其他线程调用Object.notify()或Object.notifyAll()
  • Timed waiting (计时等待)
    有几个方法有一个超时参数,调用它们导致线程进入计时等待状态。这一状态将一直保持到超时期满或者接收到适当的通知。
  • Terminated (被终止)
    因run方法正常退出而自然死亡。或因为一个没有捕获的异常终止了run方法而意外死亡。

 

如何停止一个线程

停止一个线程意味着在任务处理完任务之前停掉正在做的操作,也就是放弃当前的操作。停止一个线程可以用Thread.stop()方法,但最好不要用它。虽然它确实可以停止一个正在运行的线程,但是这个方法是不安全的,而且是已被废弃的方法。

在java中有以下3种方法可以终止正在运行的线程:

  • 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
  • 使用stop方法强行终止,但是不推荐这个方法,因为stop和suspend及resume一样都是过期作废的方法。
  • 使用interrupt方法中断线程。

详细参考:http://www.cnblogs.com/greta/p/5624839.html

 

什么是线程安全?

线程安全就是多线程访问同一代码,不会产生不确定的结果。

 

如何保证线程安全?

  • 对非安全的代码进行加锁控制
  • 使用线程安全的类
  • 多线程并发情况下,线程共享的变量改为方法级的局部变量。

 

Synchronized如何使用

synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种:

  • 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象。当一个线程获得了对象锁,其他线程如果调用此对象同一个锁的其他同步块,也会阻塞。
  • 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象。
  • 修饰一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象

 

 

 

反射

new与newInstance()的区别

  • new是一个关键字,它是调用new指令创建一个对象,然后调用构造方法来初始化这个对象,可以使用带参数的构造器
  • newInstance()是Class的一个方法,在这个过程中,是先取了这个类的不带参数的构造器Constructor,然后调用构造器的newInstance方法来创建对象。
    Class.newInstance()不能带参数,如果要带参数需要取得对应的构造器,然后调用该构造器的Constructor.newInstance(Object ... initargs)方法

 

操作系统

什么情况下会导致处理器从用户态向内核态转换?

  • 程序请求操作系统服务,执行系统调用
  • 程序运行时产生中断事件,运行程序被中断,转向中断处理程序处理
  • 程序运行时产生异常事件,运行程序被打断,转向异常处理程序工作

 

进程和线程的区别

  • 进程:具有独立功能的程序在某个数据集合上的一次运行活动,也是操作系统进行资源分配和保护的基本单位
  • 线程:进程中的一个执行流程,一个进程中可以运行多个线程。线程可与同属一个进程的其它线程共享进程所拥有的资源。

 

进程状态

就绪态、运行态、阻塞态

新建态、终止态

挂起就绪态、挂起阻塞态

 

数据结构

红黑树的五个性质

  • 每个结点要么是红的,要么是黑的。
  • 根结点是黑的。
  • 每个叶结点,即空结点(NIL)是黑的。
  • 如果一个结点是红的,那么它的俩个儿子都是黑的。
  • 对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。

 

Spring

Spring的注入方式有哪些?

  • setter注入
  • 构造器注入

 

FactoryBean和BeanFactory有什么区别?

  • BeanFactory:它是一个Factory,也就是IoC容器或对象工厂,在Spring中,所有的Bean都是由BeanFactory(也就是IoC容器)来进行管理的。
  • FactoryBean:它是一个Bean,是一个能产生或装饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和装饰模式类似.

 

数据库

事务的四个特性?

  • 原子性
  • 隔离性
  • 一致性
  • 持久性

 

事务的隔离级别

  • Read Uncommitted(读取未提交内容):所有事务都可以看到其他未提交事务的执行结果
  • Read Committed(读取提交内容):一个事务只能看见已经提交事务所做的改变
  • Repeatable Read(可重读):
  • Serializable(可串行化)

 

其他问题清单

J2SE基础

1. 九种基本数据类型的大小,以及他们的封装类。

2. Switch能否用string做参数?

3. equals与==的区别。

4. Object有哪些公用方法?

5. Java的四种引用,强弱软虚,用到的场景。

6. Hashcode的作用。

7. ArrayList、LinkedList、Vector的区别。

8. String、StringBuffer与StringBuilder的区别。

9. Map、Set、List、Queue、Stack的特点与用法。

10. HashMap和HashTable的区别。

11. HashMap和ConcurrentHashMap的区别,HashMap的底层源码。

12. TreeMap、HashMap、LindedHashMap的区别。

13. Collection包结构,与Collections的区别。

14. try catch finally,try里有return,finally还执行么?

15. Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。

16. Java面向对象的三个特征与含义。

17. Override和Overload的含义去区别。

18. Interface与abstract类的区别。

19. Static class 与non static class的区别。

20. java多态的实现原理。

21. 实现多线程的两种方法:Thread与Runable。

22. 线程同步的方法:sychronized、lock、reentrantLock等。

23. 锁的等级:方法锁、对象锁、类锁。

24. 写出生产者消费者模式。

25. ThreadLocal的设计理念与作用。

26. ThreadPool用法与优势。

27. Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。

28. wait()和sleep()的区别。

29. foreach与正常for循环效率对比。

30. Java IO与NIO。

31. 反射的作用于原理。

32. 泛型常用特点,List<String>能否转为List<Object>。

33. 解析XML的几种方式的原理与特点:DOM、SAX、PULL。

34. Java与C++对比。

35. Java1.7与1.8新特性。

36. 设计模式:单例、工厂、适配器、责任链、观察者等等。

37. JNI的使用。

Java里有很多很杂的东西,有时候需要你阅读源码,大多数可能书里面讲的不是太清楚,需要你在网上寻找答案。

推荐书籍:《java核心技术卷I》《Thinking in java》《java并发编程》《effictive java》《大话设计模式》

 

JVM

1. 内存模型以及分区,需要详细到每个区放什么。

2. 堆里面的分区:Eden,survival from to,老年代,各自的特点。

3. 对象创建方法,对象的内存分配,对象的访问定位。

4. GC的两种判定方法:引用计数与引用链。

5. GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?

6. GC收集器有哪些?CMS收集器与G1收集器的特点。

7. Minor GC与Full GC分别在什么时候发生?

8. 几种常用的内存调试工具:jmap、jstack、jconsole。

9. 类加载的五个过程:加载、验证、准备、解析、初始化。

10. 双亲委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。

11. 分派:静态分派与动态分派。

JVM过去过来就问了这么些问题,没怎么变,内存模型和GC算法这块问得比较多,可以在网上多找几篇博客来看看。

推荐书籍:《深入理解java虚拟机》

 

操作系统

1. 进程和线程的区别。

2. 死锁的必要条件,怎么处理死锁。

3. Window内存管理方式:段存储,页存储,段页存储。

4. 进程的几种状态。

5. IPC几种通信方式。

6. 什么是虚拟内存。

7. 虚拟地址、逻辑地址、线性地址、物理地址的区别。

推荐书籍:《深入理解现代操作系统》

 

TCP/IP

1. OSI与TCP/IP各层的结构与功能,都有哪些协议。

2. TCP与UDP的区别。

3. TCP报文结构。

4. TCP的三次握手与四次挥手过程,各个状态名称与含义,TIMEWAIT的作用。

5. TCP拥塞控制。

6. TCP滑动窗口与回退N针协议。

7. Http的报文结构。

8. Http的状态码含义。

9. Http request的几种类型。

10. Http1.1和Http1.0的区别

11. Http怎么处理长连接。

12. Cookie与Session的作用于原理。

13. 电脑上访问一个网页,整个过程是怎么样的:DNS、HTTP、TCP、OSPF、IP、ARP。

14. Ping的整个过程。ICMP报文是什么。

15. C/S模式下使用socket通信,几个关键函数。

16. IP地址分类。

17. 路由器与交换机区别。

网络其实大体分为两块,一个TCP协议,一个HTTP协议,只要把这两块以及相关协议搞清楚,一般问题不大。

推荐书籍:《TCP/IP协议族》

 

数据结构与算法

1. 链表与数组。

2. 队列和栈,出栈与入栈。

3. 链表的删除、插入、反向。

4. 字符串操作。

5. Hash表的hash函数,冲突解决方法有哪些。

6. 各种排序:冒泡、选择、插入、希尔、归并、快排、堆排、桶排、基数的原理、平均时间复杂度、最坏时间复杂度、空间复杂度、是否稳定。

7. 快排的partition函数与归并的Merge函数。

8. 对冒泡与快排的改进。

9. 二分查找,与变种二分查找。

10. 二叉树、B+树、AVL树、红黑树、哈夫曼树。

11. 二叉树的前中后续遍历:递归与非递归写法,层序遍历算法。

12. 图的BFS与DFS算法,最小生成树prim算法与最短路径Dijkstra算法。

13. KMP算法。

14. 排列组合问题。

15. 动态规划、贪心算法、分治算法。(一般不会问到)

16. 大数据处理:类似10亿条数据找出最大的1000个数.........等等

 

三、 项目

关于项目,这部分每个人的所做的项目不同,所以不能具体的讲。项目不再与好与不好,在于你会不会包装,有时候一个很low的项目也能包装成比较高大上的项目,多用一些专业名词,突出关键字,能使面试官能比较容易抓住重点。在聊项目的过程中,其实你的整个介绍应该是有一个大体的逻辑,这个时候是在考验你的表达与叙述能力,所以好好准备很重要。

面试官喜欢问的问题无非就几个点:

1. XXX(某个比较重要的点)是怎么实现的?

2. 你在项目中遇到的最大的困难是什么,怎么解决的?

3. 项目某个部分考虑的不够全面,如果XXXX,你怎么优化?

4. XXX(一个新功能)需要实现,你有什么思路?

其实你应该能够预料到面试官要问的地方,请提前准备好,如果被问到没有准备到的地方,也不要紧张,一定要说出自己的想法,对不对都不是关键,主要是有自己的想法,另外,你应该对你的项目整体框架和你做的部分足够熟悉。

四、 其他

你应该问的问题

面试里,最后面完之后一般面试官都会问你,你有没有什么要问他的。其实这个问题是有考究的,问好了其实是有加分的,一般不要问薪资,主要应该是:关于公司的、技术和自身成长的。

以下是我常问的几个问题,如果需要可以参考:

1. 贵公司一向以XXX著称,能不能说明一下公司这方面的特点?

2. 贵公司XXX业务发展很好,这是公司发展的重点么?

3. 对技术和业务怎么看?

4. 贵公司一般的团队是多大,几个人负责一个产品或者业务?

5. 贵公司的开发中是否会使用到一些最新技术?

6. 对新人有没有什么培训,会不会安排导师?

7. 对Full Stack怎么看?

8. 你觉得我有哪些需要提高的地方?

 

常考代码

 

 

 

 

 

Categories: 随笔