http://qsxuan.com/articles/1428.html
为什么内部类访问的局部变量必须被 final 修饰?
因为生命周期不同。局部变量在方法结束后就会被销毁,但内部类对象并不一定,这样就会导致内部类引用了一个不存在的变量。
所以编译器会在内部类中生成一个局部变量的拷贝,这个拷贝的生命周期和内部类对象相同,就不会出现上述问题。
但这样就导致了其中一个变量被修改,两个变量值可能不同的问题。为了解决这个问题,编译器就要求局部变量需要被 final 修饰,以保证两个变量值相同。
在 JDK8 之后,编译器不要求内部类访问的局部变量必须被 final 修饰,但局部变量值不能被修改(无论是方法中还是内部类中),否则会报编译错误。利用 javap 查看编译后的字节码可以发现,编译器已经加上了 final。
你了解哪些 JDK1.8 的新特性?
- 接口的默认方法和静态方法
JDK8 允许我们给接口添加一个非抽象的方法实现,只需要使用 default 关键字即可,也可以定义被 static 修饰的静态方法 - 对 HashMap 进行了改进,当单个桶的元素个数大于 6 时就会将实现改为红黑树实现,以避免构造重复的 hashCode 的攻击
- JDK8 拓宽了注解的应用场景,注解几乎可以使用在任何元素上,并且允许在同一个地方多次使用同一个注解
你知道哪些 JDK 中用到的设计模式?
- 装饰模式:java.io
- 单例模式:Runtime 类
- 简单工厂模式:Integer.valueOf 方法
- 享元模式:String 常量池、Integer.valueOf(int i)、Character.valueOf(char c)
- 迭代器模式:Iterator
- 职责链模式:ClassLoader 的双亲委派模型
- 解释器模式:正则表达式 java.util.regex.Pattern
什么是泛型、为什么要使用以及泛型擦除
泛型,即 “参数化类型”。
创建集合时就指定集合元素的类型,该集合只能保存其指定类型的元素,避免使用强制类型转换。
Java 编译器生成的字节码是不包涵泛型信息的,泛型类型信息将在编译处理是被擦除,这个过程即类型擦除。 泛型擦除可以简单的理解为将泛型 java 代码转换为普通 java 代码,只不过编译器更直接点,将泛型 java 代码直接转换成普通 java 字节码。
类型擦除的主要过程如下:
- 将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
- 移除所有的类型参数。
ConcurrentHashMap 如何保证线程安全
JDK 1.7 及以前:
ConcurrentHashMap 允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对 hash 表的不同部分进行的修改。ConcurrentHashMap 内部使用段 (Segment) 来表示这些不同的部分,每个段其实就是一个小的 hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。
详细参考:
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 的时候,会死循环。
多线程
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 方法中断线程。
什么是线程安全?
线程安全就是多线程访问同一代码,不会产生不确定的结果。
如何保证线程安全?
- 对非安全的代码进行加锁控制
- 使用线程安全的类
- 多线程并发情况下,线程共享的变量改为方法级的局部变量。
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(可串行化)
面试官喜欢问的问题无非就几个点:
1. XXX(某个比较重要的点)是怎么实现的?
2. 你在项目中遇到的最大的困难是什么,怎么解决的?
3. 项目某个部分考虑的不够全面,如果 XXXX,你怎么优化?
4. XXX(一个新功能)需要实现,你有什么思路?
其实你应该能够预料到面试官要问的地方,请提前准备好,如果被问到没有准备到的地方,也不要紧张,一定要说出自己的想法,对不对都不是关键,主要是有自己的想法,另外,你应该对你的项目整体框架和你做的部分足够熟悉。
http://www.jianshu.com/p/b5f1121c3a2d