前言
本篇面试题是整理单独整理的一篇客户端面试题, 如果有补充非常感谢在评论区留言. 更多其它一线互联网面试题请点击获取面试资料;《大厂面试资料含答案详解锦集》
这些题目是今年群友去百度, 小米, 乐视, 美团, 58, 猎豹, 360, 新浪, 搜狐等一线互联网公司面试被问到的题目. 并且大多数都整理了答案, 熟悉这些知识点会大大增加通过前两轮技术面试的几率,
JAVA SE
1. 九种基本数据类型的大小, 以及他们的封装类.
- int Integer
- short Short
- long Long
- byte Byte
- float Float
- double Double
- char Char
- boolean Boolean
- String(不算基本数据类型) Stringbuffer,Stringbuilder(非线程安全)
2. Switch 能否用 string 做参数?
Java 1.7 之前只能支持 byte,short,int,char 或其封装类及 enum 类型, 1.7 及以上才支持 string,boolean 类型也是不支持的, 会报以下错误: Cannot switch on a value of type boolean. Only convertible int values or enum constants are permitted
3.equals 与 == 的区别.
(1) 对字符串变量来说:== 比较两个对象的地址是否一致, equals 比较两个对象的值.
- String s3 = "abc", s4 = "abc"
- String s1 = new String("abc");
- String s2 = new String("abc");
- s1 == s2 //false 因为两个对象存放的地址不一致
- s1.equals(s2) // true 因为两个对象的值都是 "abc"
(2) 对于基本数据类型, 只能用 == 判断, 不能用 equals(), 而对于基本数据类型的封装类或者其他自定义类 (没有重写 equals 方法) 来说,== 比较的是地址, equals()比较的是内容
- (3) s3 == s4 // true, 因为 s3 和 s4 指向的都是同一块内存地址
- (4) StringBuffer s5 = new StringBuffer("a") ;
- StringBuffer s6 = new StringBuffer("a") ;
- s5.equals(s6) // false , 因为 StringBuffer 没有重写 equals()方法, 比较的还是内存地址, 显然两个对象内存地址是不一样的.
4.Object 有哪些公用方法?
wait(),notify(),notifyAll(),equals()--- 用来比较两个对象地址是否一致
hashCode() - 标志对象的唯一值
toString() - 对象的字符串表达形式
5. Java 的四种引用, 强弱软虚, 用到的场景.
强引用(StrongReference)--- 强引用是使用最普遍的引用. 如果一个对象具有强引用, 那垃圾回收器绝不会回收它. 当内存空间不足, Java 虚拟机宁愿抛出 OutOfMemoryError 错误, 使程序异常终止, 也不会靠随意回收具有强引用的对象来解决内存不足的问题.
软引用(SoftReference)--- 如果一个对象只具有软引用, 则内存空间足够, 垃圾回收器就不会回收它; 如果内存空间不足了, 就会回收这些对象的内存. 只要垃圾回收器没有回收它, 该对象就可以被程序使用. 软引用可用来实现内存敏感的高速缓存.
软引用可以和一个引用队列 (ReferenceQueue) 联合使用, 如果软引用所引用的对象被垃圾回收器回收, Java 虚拟机就会把这个软引用加入到与之关联的引用队列中. SoftReference 是强引用, 它保存的对象实例, 除非 JVM 即将 OutOfMemory, 否则不会被 GC 回收. 这个特性使得它特别适合设计对象 Cache. 对于 Cache, 我们希望被缓存的对象最好始终常驻内存, 但是如果 JVM 内存吃紧, 为了不发生 OutOfMemoryError 导致系统崩溃, 必要的时候也允许 JVM 回收 Cache 的内存, 待后续合适的时机再把数据重新 Load 到 Cache 中
弱引用(WeakReference)---WeakReference 是弱引用, 其中保存的对象实例可以被 GC 回收掉. 这个类通常用于在某处保存对象引用, 而又不干扰该对象被 GC 回收, 通常用于 Debug, 内存监视工具等程序中. 因为这类程序一般要求即要观察到对象, 又不能影响该对象正常的 GC 过程.
虚引用(PhantomReference)--- 就是形同虚设, 与其他几种引用都不同, 虚引用并不会决定对象的生命周期. 如果一个对象仅持有虚引用, 那么它就和没有任何引用一样, 在任何时候都可能被垃圾回收器回收.
虚引用主要用来跟踪对象被垃圾回收器回收的活动. 虚引用与软引用和弱引用的一个区别在于: 虚引用必须和引用队列 (ReferenceQueue)联合使用. 当垃圾回收器准备回收一个对象时, 如果发现它还有虚引用, 就会在回收对象的内存之前, 把这个虚引用加入到与之 关联的引用队列中.
6.HashCode 的作用
对象区别于其他对象的标识
7. ArrayList,LinkedList,Vector 的区别
ArrayList 类似于 C 中的数组, 查找方便, 插入复杂, LinedList 类似于 C 中的链表, 插入简单, 查找复杂度较高. 而 Vector 类似于 ArrayList, 但是在 Java 1.5 以后就不推荐使用了.
8. String,StringBuffer 与 StringBuilder 的区别.
StringBuffer 是 String 的封装类, 都是线程安全的, 如果字符串的内容经常改变, 则最好用, StringBuffer, 而 StringBuilder 也是可变字符串, 但是非线程安全, 因此正常情况下会比 StringBuffer 快.
9. Map,Set,List,Queue,Stack 的特点与用法.
map 根据 key 找 value
set 元素不能重复
list 类似数组
Queue 队列, 先进先出
Stack 栈, 后进先出
10. HashMap 和 HashTable 的区别.
1. 当需要同步时, 用 Hashtable, 反之用 HashMap. 但是, 因为在需要时, HashMap 可以被同步, HashMap 的功能比 Hashtable 的功能更多, 而且它不是基于一个陈旧的类的, 所以有人认为, 在各种情况下, HashMap 都优先于 Hashtable.
2. 只有 HashMap 可以让你将空值作为一个表的条目的 key 或 value.HashMap 中只有一条记录可以是一个空的 key, 但任意数量的条目可以是空的 value
11. HashMap 和 ConcurrentHashMap 的区别, HashMap 的底层源码.
有并发访问的时候用 ConcurrentHashMap, 效率比用锁的 HashMap 好.
HashMap 底层源码用 (Entry) 数组 + 链表的形式实现
12. TreeMap,HashMap,LindedHashMap 的区别.
LinkedHashMap 也是一个 HashMap, 但是内部维持了一个双向链表, 可以保持顺序
TreeMap 可以用于排序(根据键排序, 默认是升序),HashSet 是通过 HashMap 实现的, TreeSet 是通过 TreeMap 实现的, 只不过 Set 用的只是 Map 的 key,Map 的 key 和 Set 都有一个共同的特性就是集合的唯一性. TreeMap 更是多了一个排序的功能.
13.Collection 包结构, 与 Collections 的区别.
- Collection ---List ---ArrayList, LinkedList, Vector
- Set ---HashSet, TreeSet
- Map-HashMap,TreeMap,HashTable
Collection 是集合类的上级接口, 子接口主要有 Set 和 List,Map.
Collections 是针对集合类的一个帮助类, 提供了操作集合的工具方法: 一系列静态方法实现对各种集合的搜索, 排序, 线程安全化等操作.
14. try catch finally,try 里有 return,finally 还执行么?
必须执行. 如果 try 里有 return,finally 也有 return, 会执行 finally 中的 return.
15. Excption 与 Error 包结构. OOM 你遇到过哪些情况, SOF 你遇到过哪些情况.
16. Java 面向对象的三个特征与含义.
继承
封装
多态.
17. Override 和 Overload 的含义去区别.
override --- 重写父类的函数
overload - 是函数重载, 根据传入的参数 (个数, 类型) 不同来区别
18. Interface 与 abstract 类的区别.
interface 是接口, 可以有常量, 所有方法都默认是 public, 而且不能实现
abstract 类 比其他普通类多了个抽象方法, 而且是必须有抽象方法
19. Static class 与 non static class 的区别.
内部静态类不需要有指向外部类的引用. 但非静态内部类需要持有对外部类的引用. 非静态内部类能够访问外部类的静态和非静态成员. 静态类不能访问外部类的非静态成员. 他只能访问外部类的静态成员
20. java 多态的实现原理.
java 中 实例方法才有多态的, 在运行时动态绑定, 类的成员变量是在编译时就决定了.
- <pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "
- Courier New " !important; font-size: 12px !important;">
- class A { int a =1; int method() { return a ; } } class B extends A {
- int a = 2 ; int Method() { return a ; } } B bb = new B() ; System.out.println(bb.a)
- // 结果是 2 System.out.println(bb.method() ) // 结果是 2 A aa =(B) new B() ;
- System.out.println(aa.a ) // 结果是 1 System.out.println(aa.method() ) //
- 结果还是是 2, 多态
- </pre>
21. 实现多线程的两种方法: Thread 与 Runable.
继承 Thread 类, 重写 run 方法
实现 Runnable 接口
想要有返回值, 用 FutureTask, 和 Callable 接口
例子:
- public class CallableTest {
- // 创建一个计算任务, 返回累加结果, 构造器的参数是上界
- static class SumCaller implements Callable<Long> {
- private Integer count;
- public SumCaller(Integer count) {
- this.count = count;
- }
- public Long call() throws Exception {
- long sum = 0;
- for (int i = 0; i <count; i++) {
- sum += i;
- }
- return sum;
- }
- }
- private static Integer COUNT = 1000000000;
- public static void main(String[] args) throws InterruptedException,
- ExecutionException {
- SumCaller caller = new SumCaller(COUNT);
- FutureTask<Long> task = new FutureTask<Long>(caller);
- Thread thread = new Thread(task);
- thread.start();
- long sum = task.get();
- System.out.println("sum from 1 to" + COUNT + "result =" + sum);
- }
- }
22. 线程同步的方法: synchronized,lock,reentrantLock 等.
lock.lock(), 加锁, lock.unlock()释放锁,
reentrantLock, 可重入锁
synchronized 只有单一条件, 不能设置加锁时间等, 也不能设置多个锁
23. 锁的等级: 方法锁, 对象锁, 类锁.
对象锁是用于对象实例方法, 或者一个对象实例上的, 类锁是用于类的静态方法或者一个类的 class 对象上的, 我们知道, 类的对象实例可以有很多个, 但是每个类只有一个 class 对象, 所以不同对象实例的对象锁是互不干扰的, 但是每个类只有一个类锁.
24. 写出生产者消费者模式.
25. ThreadLocal 的设计理念与作用.
Java 中的 ThreadLocal 类允许我们创建只能被同一个线程读写的变量. 因此, 如果一段代码含有一个 ThreadLocal 变量的引用, 即使两个线程同时执行这段代码, 它们也无法访问到对方的 ThreadLocal 变量. 虽然所有的线程都能访问到这个 ThreadLocal 实例, 但是每个线程却只能访问到自己通过调用 ThreadLocal 的 set()方法设置的值. 即使是两个不同的线程在同一个 ThreadLocal 对象上设置了不同的值, 他们仍然无法访问到对方的值. 内部实现用同步 Map.
- public class ThreadLocalExample {
- public static class MyRunnable implements Runnable {
- private ThreadLocal threadLocal = new ThreadLocal();
- @Override
- public void run() {
- threadLocal.set((int) (Math.random() * 100D));
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- }
- System.out.println(threadLocal.get());
- }
- }
- public static void main(String[] args) {
- MyRunnable sharedRunnableInstance = new MyRunnable();
- Thread thread1 = new Thread(sharedRunnableInstance);
- Thread thread2 = new Thread(sharedRunnableInstance);
- thread1.start();
- thread2.start();
- }
- }
26. ThreadPool 用法与优势.
在多线程环境中使用 Thread Pool, 可以提高运行效率, 不用每次新建一个线程, 循环利用线程.
- public class TestFixedThreadPool {
- public static void main(String[] args) {
- // 创建一个可重用固定线程数的线程池
- ExecutorService pool = Executors.newFixedThreadPool(2);
- // 创建实现了 Runnable 接口对象, Thread 对象当然也实现了 Runnable 接口
- Thread t1 = new MyThread();
- Thread t2 = new MyThread();
- Thread t3 = new MyThread();
- Thread t4 = new MyThread();
- Thread t5 = new MyThread();
- // 将线程放入池中进行执行
- pool.execute(t1);
- pool.execute(t2);
- pool.execute(t3);
- pool.execute(t4);
- pool.execute(t5);
- // 关闭线程池
- pool.shutdown();
- }
- }
27. Concurrent 包里的其他东西: ArrayBlockingQueue,CountDownLatch 等等.
28. wait()和 sleep()的区别.
1. sleep()不释放同步锁, wait()释放同步锁.
2. sleep 是 Thread 类的方法, wait 是 Object 的方法. wait,notify 和 notifyAll 只能在同步控制方法或者同步控制块里面使用, 而 sleep 可以在任何地方使用
29.foreach 与正常 for 循环效率对比.
使用 for, 更高效率. 使用 foreach, 更安全.
如果在使用 foreach 遍历对象的过程中, 其他线程修改了 List 的内容, 例如添加或者删除, 就会出现不可知的错误, 而使用 foreach 则能够正确抛出错误信息.
30. Java IO 与 NIO.
字符流: reader
writer
字节流: inputStream
outputStream
NIO : Buffer 和 channel
31. 反射的作用与原理.
指的是我们可以于运行时加载, 探知, 使用编译期间完全未知的 classes. 换句话说, Java 程序可以加载一个运行时才得知名称的 class, 获悉其完整构造(但不包括 methods 定义), 并生成其对象实体, 或对其 fields 设值, 或唤起其 methods.</pre>
用途: Java 反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类; 在运行时构造任意一个类的对象; 在运行时判断任意一个类所具有的成员变量和方法; 在运行时调用任意一个对象的方法; 生成动态代理.</pre>
32. 泛型常用特点, List<String > 能否转为 List<Object>.
如果 List<Object > 作为函数参数, List<String > 作为要传进来的参数, 答案是不能. 正确理解泛型概念的首要前提是理解类型擦除(type erasure). Java 中的泛型基本上都是在编译器这个层次来实现的. 在生成的 Java 字节代码中是不包含泛型中的类型信息的. 使用泛型的时候加上的类型参数, 会被编译器在编译的时候去掉. 这个过程就称为类型擦除. 如在代码中定义的 List<Object > 和 List<String > 等类型, 在编译之后都会变成 List.JVM 看到的只是 List, 而由泛型附加的类型信息对 JVM 来说是不可见的.
- public void inspect(List<Object> list) {
- for (Object obj : list) {
- System.out.println(obj);
- }
- list.add(1); // 这个操作在当前方法的上下文是合法的. }public void test() {
- List<String> strs = new ArrayList<String>();
- inspect(strs); // 编译错误
- }
- public void wildcard(List<?> list) {
- list.add(1);// 编译错误
- }
如上所示, 试图对一个带通配符的泛型类进行操作的时候, 总是会出现编译错误. 其原因在于通配符所表示的类型是未知的.
因为对于 List<?>中的元素只能用 Object 来引用, 在有些情况下不是很方便. 在这些情况下, 可以使用上下界来限制未知类型的范围. 如 List<? extends Number > 说明 List 中可能包含的元素类型是 Number 及其子类. 而 List<? super Number > 则说明 List 中包含的是 Number 及其父类. 当引入了上界之后, 在使用类型的时候就可以使用上界类中定义的方法. 比如访问 List<? extends Number > 的时候, 就可以使用 Number 类的 intValue 等方法.
33. 解析 xml 的几种方式的原理与特点: DOM,SAX,PULL.
DOM 解析: 将整个 xml 加载到内存中, 比较方便插入和查找相邻节点, 但是耗内存, 手机用得较少
SAX 解析: simple API for xml,SAX 解析 xml 文件采用的是事件驱动, 进而调用一些回调方法(CallBack), 比如
- startDocument()
- endDocument()
- startElement(String namespaceURI, String localName, String qName, Attributes atts)
- endElement(String uri, String localName, String name)
- characters(char[] ch, int start, int length)
SAX 解析适用于移动设备
PULL 解析: 和 SAX 类似, Android 自带 jar 包, 根据 EventType 来进行, 比如
- XmlPullParser.START_DOCUMENT
- XmlPullParser.END_DOCUMENT
- XmlPullParser.START_TAG
- XmlPullParser.END_TAG
- XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
- XmlPullParser parser = factory.newPullParser();
- parser.setInput(inputStream, "utf-8");
- int eventType = parser.getEventType();
- eventType = parser.next();
34. Java 与 C++ 对比.
35. Java1.7 与 1.8 新特性.
1.7;
1. map 集合支持并发请求, 且可以写成 Map map = {name:"xxx",age:18};
2.switch 中可以使用字串了
3. 运用 List<String> tempList = new ArrayList<>(); 即泛型实例化类型自动推断
4. 两个 char 间的 equals bool Character.equalsIgnoreCase(char ch1, char ch2)
1.8;
1. lambda 表达式:
原来代码:
- List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
- Collections.sort(names, new Comparator<String>() {
- @Override
- public int compare(String a, String b) {
- return b.compareTo(a);
- }
- });
加入 lambda 表达式:
- Collections.sort(names, (String a, String b) -> {
- return b.compareTo(a);
- });
更简洁:
Collections.sort(names, (String a, String b) -> b.compareTo(a));
更更简洁:
Collections.sort(names, (a, b) -> b.compareTo(a));
36. 设计模式: 单例, 工厂, 适配器, 责任链, 观察者等等.
37. JNI 的使用
JVM
内存模型以及分区, 需要详细到每个区放什么.
堆里面的分区: Eden,survival from to, 老年代, 各自的特点.
对象创建方法, 对象的内存分配, 对象的访问定位.
GC 的两种判定方法: 引用计数与引用链.
GC 的三种收集方法: 标记清除, 标记整理, 复制算法的原理与特点, 分别用在什么地方, 如果让你优化收集方法, 有什么思路?
GC 收集器有哪些? CMS 收集器与 G1 收集器的特点.
Minor GC 与 Full GC 分别在什么时候发生?
几种常用的内存调试工具: jmap,jstack,jconsole.
类加载的五个过程: 加载, 验证, 准备, 解析, 初始化.
双亲委派模型: Bootstrap ClassLoader,Extension ClassLoader,ApplicationClassLoader.
分派: 静态分派与动态分派.
持续更新中~
更多其它一线互联网面试题请点击获取面试资料;《大厂面试资料含答案详解锦集》
来源: http://www.jianshu.com/p/902aa86cc770