不积硅步无以至千里
题目整理于网络, 就不一一标明出处,在这里统一谢过
一、String特性。StringBuffer 和 StringBuilder 区别
String a = "str"; String b = new String("str");问 a == b , a.equals(b) 的值是true还是false?
这里涉及到 == 与 equals 的区别:
==:比较引用类型比较的是地址值是否相同
equals:比较引用类型默认也是比较地址值是否相同,而String类重写了equals()方法,比较的是内容是否相同。
String a = "str"; ,"str" 存到方法区的字符串常量池。而String b = new String("str");,new String() 存到堆中,再指向常量池的"str"。
用 == 时,a指向的是字符串常量池地址,而b指向的是 new String() 堆中存放地址。所以必然false。而String 的equals 是比较内容。所以是 true。
关于String要知道它是被final修饰的不可变类。频繁修改最好用 StringBuffer 或 StringBuilder。二者的区别,StringBuilder效率高,线程不安全。StringBuffer线程安全。
二、ArrayList 和 LinkedList 原理、区别以及底层数据结构
区别:
ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
以第三点为例,为什么新增删除 LinkedList占优势呢?看了源码就会了解到。 ArrayList 底层结构是数组,首先数组是不可变的,新增要检查数组大小是否满足,不满足需要扩容,扩容就需要新建数组,然后将原数组copy到新数组,再制空原数组,在新数组新增。删除时,ArrayList会将后面部分的元素依次往上挪一个位置(就是copy)。
有时候会问到怎么保证ArrayList 线程安全。用Collections.synchronizedList()或改用 Vector。原理是方法前加入了synchronize关键字实现加锁。
三、HashMap、HashTable、ConcurrentHashMap 原理、源码、数据结构,线程是否安全
HashMap是数组加链表结构。通过key的hashcode 找到数组角标。再遍历链表。
HashTable和HashMap区别,属于线程安全,key value 不能为 null。
ConcurrentHashMap也是线程安全,结构可理解成 分裂数组+HashTable。
效率比HashTable高,因为HashTable是整个Map加锁,ConcurrentHashMap是把锁加到 各个分裂数组上。
五、Lock 和 synchronize 实现原理与区别。简述乐观锁悲观锁。分布式锁实现方式
synchronized是托管给JVM执行的,而lock是java写的控制锁的代码。synchronized在锁定时如果方法块抛出异常,JVM 会自动将锁释放掉,不会因为出了异常没有释放锁造成线程死锁。但是 Lock 的话就享受不到 JVM 带来自动的功能,出现异常时必须在 finally 将锁释放掉,否则将会引起死锁。在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize。
分布式锁实现方式:
基于数据库实现,
基于缓存(Redis,memcached,tair)实现,
基于Zookeeper实现。
分布式锁如何实现呢?
悲观锁:一段执行逻辑加上悲观锁,不同线程同时执行时,只能有一个线程执行,其他的线程在入口处等待,直到锁被释放。
乐观锁:一段执行逻辑加上乐观锁,不同线程同时执行时,可以同时进入执行,在最后更新数据的时候要检查这些数据是否被其他线程修改了(版本和执行初是否相同),没有修改则进行更新,否则放弃本次操作。
悲观锁的实现:
//0.开始事务
begin;/begin work;/start transaction; (三者选一就可以)
//1.查询出商品信息
select status from t_goods where id=1 for update;
//2.根据商品信息生成订单
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品status为2
update t_goods set status=2;
//4.提交事务
commit;/commit work;
乐观锁的实现
1.查询出商品信息
select (status,status,version) from t_goods where id=#{id}
2.根据商品信息生成订单
3.修改商品status为2
update t_goods
set status=2,version=version+1
where id=#{id} and version=#{version};
六、SpringMVC流程。常用注解。Spring的IOC和AOP
SpringMVC流程:
1.用户发送请求至前端控制器DispatcherServlet。
2.DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3.处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象
4.及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
5.DispatcherServlet调用HandlerAdapter处理器适配器。
6.HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
7.Controller执行完成返回ModelAndView。
8.HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
9.DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
10.ViewReslover解析后返回具体View。
11.DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
12.DispatcherServlet响应用户。
IOC AOP 懒得打字了
七、事务相关
项目中事务处理方案。
4种事务特性:
原子性 (atomicity):强调事务的不可分割.
一致性 (consistency):事务的执行的前后数据的完整性保持一致.
隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰
持久性(durability) :事务一旦结束,数据就持久到数据库
5种隔离级别:
DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别
未提交读(read uncommited) :脏读,不可重复读,虚读都有可能发生
已提交读 (read commited):避免脏读。但是不可重复读和虚读有可能发生
可重复读 (repeatable read) :避免脏读和不可重复读.但是虚读有可能发生
串行化的 (serializable) :避免以上所有读问题
7种传播行为:
保证同一个事务中
PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
保证没有在同一个事务中
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行
分布式事务处理方案
十、常用那些设计模式,说出原理,已经框架中用到哪些。单例的几种写法
23种设计模式至少要了解Spring框架用到的一些设计模式。bean单例 beanfactory工厂 AOP动态代理等。
单例有饿汉式,懒汉式,静态内部类等方式。这些方式并非真正安全,可以用反射拿到,用枚举可以避免。
十一、常用中间件RabbitMQ,kafka等,原理、区别、优缺点
中间件的应用场景。
RabbitMQ是一个AMQP实现,传统的messaging queue系统实现,基于Erlang。老牌MQ产品了。AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量还在其次。
Kafka是linkedin开源的MQ系统,主要特点是基于Pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输,0.8开始支持复制,不支持事务,适合产生大量数据的互联网服务的数据收集业务。
十二、缓存:Redis原理,数据结构,集群几种方式。和memcache区别
十三、HTTP协议,RPC协议,Socket协议
十四、Nginx实现负载均衡的几种方式
轮询,随机,哈希,加权轮询,加权随机,最小连接数等。
十五、JAVA中的堆和栈
栈是一种具有后进先出性质的数据结构,也就是说后存放的先取,先存放的后取。
堆是一种经过排序的树形数据结构,每个结点都有一个值。通常我们所说的堆的数据结构,是指二叉堆。堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。由于堆的这个特性,常用来实现优先队列,堆的存取是随意的。
为什么要划分堆和栈
1、从软件设计的角度看,栈代表了处理逻辑,而堆代表了数据。这样分开,使得处理逻辑更为清晰。
2、堆与栈的分离,使得堆中的内容可以被多个栈共享。一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另一方面,堆中的共享常量和缓存可以被所有栈访问,节省了空间。
3、栈因为运行时的需要,比如保存系统运行的上下文,需要进行地址段的划分。由于栈只能向上增长,因此就会限制住栈存储内容的能力。而堆不同,堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分,使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可。
4、体现了Java面向对象这一核心特点(也可以继续说一些自己的理解)
十六、线程池
线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,然后在需要执行新的任务时重用这些线程而不是新建一个线程。
使用线程池的好处
1、线程池改进了一个应用程序的响应时间。由于线程池中的线程已经准备好且等
待被分配任务,应用程序可以直接拿来使用而不用新建一个线程。
2、线程池节省了CLR 为每个短生存周期任务创建一个完整的线程的开销并可以在任务完成后回收资源。
3、线程池根据当前在系统中运行的进程来优化线程时间片。
4、线程池允许我们开启多个任务而不用为每个线程设置属性。
5、线程池允许我们为正在执行的任务的程序参数传递一个包含状态信息的对象引用
6、线程池可以用来解决处理一个特定请求最大线程数量限制问题。
十六、mysql的优化经验
1、对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2、应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
3、尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低
查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个
比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
4、任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
5、避免频繁创建和删除临时表,以减少系统表资源的消耗。诸如此类,等等等等......
java高并发解决方案
十七、强引用,软引用和弱引用的区别
强引用:
只有这个引用被释放之后,对象才会被释放掉,只要引用存在,垃圾回收器永远不会回收,这是最常见的New出来的对象。
软引用:
内存溢出之前通过代码回收的引用。软引用主要用户实现类似缓存的功能,在内存足够的情况下直接通过软引用取值,无需从繁忙的真实来源查询数据,提升速度;当内存不足时,自动删除这部分缓存数据,从真正的来源查询这些数据。
弱引用:
第二次垃圾回收时回收的引用,短时间内通过弱引用取对应的数据,可以取到,当执行过第二次垃圾回收时,将返回null。弱引用主要用于监控对象是否已经被垃圾回收器标记为即将回收的垃圾,可以通过弱引用的isEnQueued方法返回对象是否被垃圾回收器标记。
十八、数组在内存中如何分配
1、简单的值类型的数组,每个数组成员是一个引用(指针),引用到栈上的空间(因为值类型变量的内存分配在栈上)
2、引用类型,类类型的数组,每个数组成员仍是一个引用(指针),引用到堆上的空间(因为类的实例的内存分配在堆上)
23种设计模式完整总结看这里
十九、mybatis如何处理结果集
MyBatis的结果集是通过反射来实现的。并不是通过get/set方法。在实体类中无论是否定义get/set()方法,都是可以接收到的。
深入理解java的接口和抽象类
二十、cookie和session的区别,分布式环境怎么保存用户状态
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性
能,考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
分布式环境下的session(举例两种):
服务器session复制
原理:任何一个服务器上的session发生改变(增删改),该节点会把这个 session的
所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要session,以
此来保证Session同步。
优点:可容错,各个服务器间session能够实时响应。
缺点:会对网络负荷造成一定压力,如果session量大的话可能会造成网络堵塞,拖
慢服务器性能。
session共享机制
使用分布式缓存方案比如memcached、redis,但是要求Memcached或Redis必须是集群。
Nginx反向代理,负载均衡,redis session共享,keepalived高可用
设计模式六大原则 (1):单一职责原则
设计模式六大原则(2):里氏替换原则
设计模式六大原则(3):依赖倒置原则
设计模式六大原则(4):接口隔离原则
设计模式六大原则(5):迪米特法则
设计模式六大原则(6):开闭原则
Spring 面试问题 TOP 50
Redis最常见的面试题
常问的数据库方面问题
常见计算机网络问题
springBoot面试题
多线程与并发相关面试题
给你一组字符串如:7i8hy4jjnb2.让你编程输出里面的数字:7842
String str = "7i8hy4jjnb2";
char[] ch = str.toCharArray();
int bytes = ch.length;
for(int i=bytes;i--;){
if(ch[i]>255){
bytes++;
System.out.println(ch[i]);
}
}
深拷贝和浅拷贝的区别是什么?
浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深拷贝把要复制的对象所引用的对象都复制了一遍。
用 wait-notify 写一段代码来解决生产者-消费者问题?
请参考答案中的示例代码。只要记住在同步块中调用 wait() 和 notify()方法,如果阻塞,通过循环来测试等待条件。
【生产者】
package com.edu.chapter03.test;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Producer implements Runnable {
private final Vector sharedQueue;
private final int SIZE;
public Producer(Vector sharedQueue, int size) {
this.sharedQueue = sharedQueue;
this.SIZE = size;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 7; i++) {
System.out.println("Produced:" + i);
try {
produce(i);
} catch (InterruptedException ex) {
Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private void produce(int i) throws InterruptedException {
//wait if queue is full
while (sharedQueue.size() == SIZE) {
synchronized (sharedQueue) {
System.out.println("Queue is full " + Thread.currentThread().getName()
+ " is waiting , size: " + sharedQueue.size());
sharedQueue.wait();
}
}
//producing element and notify consumers
synchronized (sharedQueue) {
sharedQueue.add(i);
sharedQueue.notifyAll();
}
}
}
【消费者】
package com.edu.chapter03.test;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Consumer implements Runnable {
private final Vector sharedQueue;
private final int SIZE;
public Consumer(Vector sharedQueue, int size) {
this.sharedQueue = sharedQueue;
this.SIZE = size;
}
@Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
System.out.println("Consumer: " + consume());
Thread.sleep(50);
} catch (InterruptedException ex) {
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private int consume() throws InterruptedException {
//wait if queue is empty
while (sharedQueue.isEmpty()) {
synchronized (sharedQueue) {
System.out.println("Queue is empty " + Thread.currentThread().getName()
+ " is waiting , size: " + sharedQueue.size());
sharedQueue.wait();
}
}
//otherwise consume element and notify waiting producer
synchronized (sharedQueue) {
sharedQueue.notifyAll();
return (Integer) sharedQueue.remove(0);
}
}
}
【测试函数】
package com.edu.chapter03.test;
import java.util.Vector;
public class ProducerConsumerSolution {
public static void main(String[] args) {
Vector sharedQueue = new Vector();
int size = 4;
Thread prodThread = new Thread(new Producer(sharedQueue, size), "Producer");
Thread consThread = new Thread(new Consumer(sharedQueue, size), "Consumer");
prodThread.start();
consThread.start();
}
3*0.1 == 0.3 将会返回什么?true 还是 false?
false,因为有些浮点数不能完全精确的表示出来。
递归调用可以导致栈溢出
不断创建对象可以导致堆溢出, 对象是存在堆里面的
Spring框架中都用到了哪些设计模式?
代理模式:在AOP和remoting中被用的比较多。
单例模式:在spring配置文件中定义的bean默认为单例模式。
模板方法模式:用来解决代码重复的问题。
前端控制器模式:Spring提供了DispatcherServlet来对请求进行分发。
依赖注入模式:贯穿于BeanFactory / ApplicationContext接口的核心理念。
工厂模式:BeanFactory用来创建对象的实例。
数据库三范式
1 、第一范式(1NF)
在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。
所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。
在第一范式(1NF)中表的每一行只包含一个实例的信息。简而言之,第一范式要求数据表中的每一列(每个字段)必须是不可拆分的最小单元。
2、 第二范式(2NF)
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。
第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。简而言之,第二范式要求表中的所有列,都必须依赖于主键,而不能有任何一列与主键没有关系。
3 、第三范式(3NF)
满足第三范式(3NF)必须先满足第二范式(2NF)。第三范式(3NF)要求一个数据库表中不包含其它表中已包含的非主关键字信息。简而言之,第三范式要求表中的每一列只与主键直接相关而不是间接相关,表中的每一列只能依赖于主键。
说一下Spring的核心模块
Spring Core【核心容器】:
核心容器提供了Spring的基本功能。核心容器的核心功能是用IOC容器来管理类的依赖关系。
Spring AOP【面向切面】:
Spring的AOP模块提供了面向切面编程的支持。
SpringAOP采用的是纯Java实现,采用基于代理的AOP实现方案,AOP代理由IOC容
器负责生成、管理,依赖关系也一并由IOC容器管理。
Spring ORM【对象实体映射】:
提供了与多个第三方持久层框架的良好整合。
Spring DAO【持久层模块】:
Spring进一步简化DAO开发步骤,能以一致的方式使用数据库访问技术,用统一的方式调用事务管理,避免具体的实现侵入业务逻辑层的代码中。
Spring Context【应用上下文】:
它是一个配置文件,为Spring提供上下文信息,提供了框架式的对象访问方法。
Spring Web【Web模块】:
提供了基础的针对Web开发的集成特性。
Spring MVC【MVC模块】:
提供了Web应用的MVC实现。Spring的MVC框架并不是仅仅提供一种传统的实现,它提供了一种清晰的分离模型。
redis常用的五种数据类型
1.String(字符串)
String是简单的 key-value 键值对,value 不仅可以是 String,也可以是数字。它是Redis最基本的数据类型,
一个redis中字符串value最多可以是512M。
2.Hash(哈希)
Redis hash 是一个键值对集合,对应Value内部实际就是一个HashMap,Hash特别适合用于存储对象。
3.List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。
底层实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部
分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数
据结构。
4.Set(集合)
Redis的Set是String类型的无序集合,它的内部实现是一个 value永远为null的
HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提
供判断一成员是否在集合内的原因。
5.zset(有序集合)
Redis zset 和 set 一样也是String类型元素的集合,且不允许重复的成员,不同的是每
个元素都会关联一个double类型的分数,用来排序。
7.java反射(java.lang.reflect)
程序一般原理:Java创建对象——>知道类的源码——>调用构造、属性、方法
反射原理 :没有源码,只有字节码——>反射类属性、方法和父类实现的接口——>调用方法、构造
反射 就是把一个类 用其他的类来表示 ;
获取类的字节码:
- 类路径(包名+类名).class ( Class c=包名+类名.class;)
- Class.forName("类路径");
- 通过类的对象 .getClass();
获取父类:Class suoerc=c.getSupperclass();
获取实现的接口:Class[] interfaces=c.getInterfaces();
获取类的属性(Filed(java.lang.reflect)):
Filed[] fs=c.getFilelds();获取public 属性(自身与父类继承过来的)
Filed[] fs=c.getDeclaredFields();获取自身所有的属性
获取类的方法(Method(java.lang.reflect)):
Method[] ms=c.getDeclaredMethods();获取自身所有的方法
Method[] ms2=c.getMethods();获取public 方法(自身与父类,父类的父类继承过来的)
获取类的构造方法(Constructor (java.lang.reflect)):
Constructor[] crs=c.getConstructors() ;
HashMap实现原理分析
JAVA中的值传递和引用传递
JAVA中的IO流
Java中的NIO实现原理
MySql面试题
大型网站海量数据解决方案
在一个千万级的数据库查寻中,如何提高查询效率?
基于Redis分布式缓存实现
【设计模式总结】对常用设计模式的一些思考
40个Java多线程问题总结
死锁,如何写一个死锁,如何避免死锁
Java日志框架:logback详解
Java日志框架:slf4j作用及其实现原理
Redis从入门到精通:初级篇
Redis从入门到精通:中级篇
什么是微服务架构
SpringBoot相关
java基础,常见面试题40道
activeMQ了解
activeMQ面试题
activeMQ使用场景
ZooKeeper相关
Hashcode的作用
反射的实例
http://blog.csdn.net/xuefeng_yang/article/details/49497415
http://www.cnblogs.com/zhaoyanjun/p/6074887.html