这是从网上看到的一套java面试题, 答案只是一个大概, 另外题目质量良莠不齐, 斟酌参考(JVM的部分暂时没有答案)html
答: JDK(Java Development Kit)是java开发工具包, 是针对开发人员提供的一套开发环境, 其中包含了jre(程序运行环境,标准类库class文件)以及编译器javac等一系列工具. JRE(Java Runtime Environment)是Java运行时环境, 针对生产环境发布, 其中包含了JVM虚拟机以及标准类库的class文件.前端
另外, JVM(Java Virtual Machine)Java虚拟机, 将class字节码指令翻译为机器指令, 是跨平台的核心.java
答: == 能够用于值类型和对象类型, 可用于断定两个值是否相等. 当用于引用类型时, 用来断定两个对象地址, 便是否指向相同的内存空间. equals()方法的Object的默认实现使用==比较, 也就是说默认就是比较对象地址是否相等, 但类库中的不少类, 包括包装类型, String等均重写了该方法. equals用来比较对象内容是否相等, 对于自定义类型, 能够重写此方法实现对象自定义的比较逻辑, 这个逻辑通常要求比较严谨复杂,因此同时也要重写hashCode()方法,毕竟若是能在实现中先使用hashCode比较可能会对性能有积极影响.mysql
答: 不对! hashCode()相同, 由于可能存在hash碰撞, 也可能致使不一样的对象计算出相同的hash值. 另外, hashCode()和equals()方法都是Object对象的方法, 自定义类型可能会覆盖也可能不覆盖这两个方法, 因此说他们必定为true是不对的. 通常而言, 若是equals()方法返回true, 则hashCode()的值相同, 反之不必定成立.程序员
答: final 能够修饰域变量, 方法, 类. 修饰的域变量的值不能被从新赋值, 修饰的方法不能在子类中被重写, 修饰的类不能被继承. final是保证程序不被恶意篡改的手段.web
final常常是static一块儿使用.
final的优势: 1.提示了性能, jvm和程序会缓存变量, 方法是静态绑定的; 2. 安全地在多线程环境下共享变量,没有多余开销;
final变量通常要大写, 局部变量须要声明时就赋值, 但域变量能够在构造函数, 初始化块儿内赋值.面试
答: 1 就近舍入也叫银行家舍入. 方法是原值+0.5后下取整.ajax
答: 不属于! 基本数据类型只有8种. boolean byte short int long float double char . String是引用类型, 并将其设置为final, String的具体字符串值在常量池中存在.redis
答: 除了基本的String, 还有StringBuidler和StringBuffer. String作字符串操做时效率过低, 由于其不可变性, 可能会有大量对象建立而占用大量内存. 然后二者用来处理字符串对象, 不一样之处在于StringBuffer时线程安全的, StringBuilder为了效率考虑线程不安全.算法
答: 不同, 字符串存在常量池中, 若是常量池中不存在, 则建立; 若是使用new 建立, 则须要在堆上建立String对象, 并在常量池中建立字符串"i"(若是不存在的话).
答: 有若干方法, 最简单的是使用StringBuilder#reverse()方法.
另外还有,(1).二分递归;(2),charAt()拼接字符串;(3)数组反转拼接;(4)数组字符首尾替换;(5)使用Stack
答:
charAt(); compareTo();compareToIgnoreCase();concat();contains();static copyValueOf();endsWith();equals();equalsIgnoreCase(); static format(); getBytes();getChars(); indexOf(); isEmpty(); lastIndexOf();length();matchs();replace();replaceAll();replaceFirst();spilit();startsWith();subString();toCharArray();toLowerCase();toUpperCase();trim();valueOf();
;
答: 抽象类中的抽象方法不是必须的, 但抽象方法必定在抽象类中; 即便没有抽象方法的抽象类也不能被实例化.
答: (1).抽象类不能被实例化;(2).抽象方法用abstract修饰且没有实现;(3).有抽象方法的类必须声明为抽象类;(4).抽象类的子类若是不是抽象类就必须实现抽象方法;(5).抽象方法不能为static;(6).抽象类能够有构造函数;
答: 不能! final的类不能被其余类继承, 而抽象类中的方法必须被子类实现, 自己有冲突. 若是在idea中声明, 编译器会报非法组合的修饰符.
答: (1).本质上抽象类是类Class,接口是彻底不一样的一种类型Interface;(2)接口不能有构造函数,抽象类能够有;(3).接口中的方法无修饰符(但其是public),接口中的方法能够被普通方法的修饰符修饰(抽象方法除外,不能是private,static);(4)接口能够被多继承, 抽象类只能单继承;(5)接口中的属性默认是static final的,抽象类能够是任意;(6)1.8以前接口方法必须被实现类实现, 抽象类的抽象方法必须被子类实现,1.8以后接口能够有默认实现了;(7)抽象类能够有main方法,并能够执行;
答: 字节流和字符流; 输入流和输出流;缓冲流和非缓冲流;
答: BIO:阻塞IO; NIO: new io 又叫非阻塞IO, 多路复用器seletctor; AIO : 异步IO. 参看:以Java的视角来聊聊BIO、NIO与AIO的区别
BIO 是同步阻塞IO, 读写操做由单独的线程完成, 若是出现资源等待则线程被阻塞,操做系统级别来讲会出现线程上下文切换, 致使性能开销, 因此BIO适合少许读写操做, 不适合大量并发操做如web环境.
NIO 是同步非阻塞IO, NIO基于事件驱动, 目的就是解决BIO的高并发问题. NIO采用多路复用机制, 当有流须要读写时才使用线程处理, 不然不作操做.NIO抽象出Channal和Buffer的概念, 以及Selector, 而不针对Stream直接操做, 而是使用Buffer和Channel, Buffer中使用DirectByteBuffer性能更快, 由于这个类不使用java堆,直接使用系统接口申请内存,减小了数据复制转移等操做的开销,但也容易致使OOM. Selector多路复用的基础类, 单线程处理多个Channel
AIO 是异步非阻塞IO, java7发布. 是在数据准备好以后通知线程处理的方式, 而不是NIO的轮训, AIO是真正的同步, 底层调用了系统级别的API实现.
答:
canExecute();canRead();canWrite();compareTo();createNewFile();createTempFile();delete();deleteOnExit();equals();getAbsoluteFile();getFreeSpace();getName();getParent();getParentFile();getPath();isAbsolute();isDirectory();isFile();isHidden();lastModified();length();list();listFiles(),listRoots();mkdir();mkdirs();renameTo();setExecutable();setLastModified();setReadable();setWritable();toURI();
答:
Array,String
,java.util
包下面的Collection,List,ArrayList,LinkedList,Vector,Stack,Map,HashMap,WeakHashMap,LinkedHashMap,HashTable,TreeTable,Set,HashSet,TreeSet,LinkedSet,Queue,
对应的并发容器类,阻塞容器类.
答: Collection 是集合接口,提供了对集合对象最基本的通用接口方法. 定义了集合最大化统一操做方式. Collections 是一个工具类, 包含了各类集合操做的静态方法, 这个类不能实例化, 只是一个工具类, 相似Arrays.
答: List是有序集合,元素能够重复, Set的元素不能重复,只容许一个null元素; List和Set都继承自Collection; Map是键值对,键能够做为索引来查找值, 能够有多个null值,但只有一个null键.
答: 简单的说, HashTable 是线程安全的, HashMap 是线程不安全的, 也正由于此, HashMap的效率更高. 从内部实现看, HashMap和HashTable实现上几乎彻底相同, 只不过HashTable是用synchronized的. HashTable不容许null作键, HashMap容许null作键, 但仅容许一个.ConcurrentHashMap是HashTable的替代, 比后者具备更好扩展性.
答: 最大的区别是 TreeMap 是有序的, HashMap 并不能保证元素的顺序. HashMap 继承了AbstractMap,TreeMap继承了SortedMap. HashMap适用于Map中插入,删除和定位. TreeMap适用于按天然顺序和自定义顺序遍历(key).
答: 基于1.8. HashMap的内部实现为一个数组, 每一个元素称为桶bucket, 每一个元素为Node, 包含key, value, Node类型的next, 还有个hash值. HashMap的初始容量是16, 默认填充因子是0.75, 当容量不够时其扩容按N*2扩容. 当桶中元素不大于8时数据结构是个列表, 当大因而转化为红黑树, 当红黑树元素小于6时退化为列表.
hash的方法和定位, 先对hash值计算, 方法是高16位与低16位异或运算, 而后用容量n-1与hash结果与运算, 算出下标.
resize 的处理, 由于容量都是2的N次幂, 因此调整size的时候能够原位不变, 在高位填充随机的0或1. 即移动一个2次幂的位置. resize能够均匀的把冲突的节点分布到新的桶中了.
答: HashSet 基于 HashMap实现. 但仅仅使用key来实现各类特性. 内部定义了一个假值用来操做.
答: ArrayList随机访问比较高效, LinkedList更适合作增长删除修改操做. 分开来讲, ArrayList是以数组的方式实现, 能经过索引快速定位. LinkedList是链表, 每一个元素保存了前一节点和后一节点的引用.
答: List#toArray()方法将List转为数组, new ArrayList(Arrays.asList()) 方法将数组转为List.
答: 都基于数组实现, Vector出现较早,提供了线程安全性, ArrayList效率更高. Vector默认增加为原容量2倍, ArrayList默认增加为原容量1.5倍+1.
答: Array是数组, ArrayList是列表实现了List接口. ArrayList能够动态扩容, Array的容量是固定的.
答: 当队列为空时poll()会返回null, remove()则抛出异常.
答: HashTable, Vector,Stack, concurrent包下面的集合类, ConcurrentHashMap,ConcurrentSkipListMap、ConcurrentSkipListSet、ConcurrentLinkedQueue、ConcurrentLinkedDeque等, CopyOnWriteArrayList, CopyOnWriteArraySet.
答: Iterator是个接口, 实现了该接口的类通常是集合类, 可以遍历集合中的元素. 迭代器是一种设计模式. Java中的Iterator只能单向移动, 包含的方法next(),hasNext(),remove(). 迭代器取代了原来的Enumeration接口.
答:
while(iterator.hasNext()){...}
Iterator的特色是更加安全, 由于它能够确保在遍历的集合元素被修改后抛出ConcurrentModiicationException
答: ListIterator 扩展了 Iterator. 固然Iterator有的功能ListIterator就有. 但ListIterator新增了一些额外的功能, 好比添加,替换获取前面或后面元素的索引位置. 另外, ListIterator是双向的.
答: 可使用Collections类的静态方法unmodifiableCollection()方法建立只读集合. 任何改变集合的操做都将抛出
java.lang.UnsupportedOperationException
答: 并行是针对多核CPU的, 指多个任务能够同时分别在各自CPU上运行; 并发是指多个线程争夺同一个CPU资源(时间片), 存在上下文切换. CPU一个时间点只能处理一个任务.
答: 线程是系统调度资源的最小单位, 进程是系统分配资源的最小单位, 一个程序包含至少一个进程, 一个进程包含至少一个线程.
答: 守护线程是针对用户线程的, 用户线程是程序启动的线程, 守护线程通常是有JVM启动, 但也不必定. 对于任何线程, 都可以在启动前调用setDeamon(true)方法设置为守护线程.
答: Thread, Runnable, Callable
答: callable有返回值, runnable没有.
答: NEW, RUNABLE, TERMINATED, BLOCKED, WAITING,TIMED_WAITING
答: (1).sleep()是线程方法,wait()是Object的方法;(2)sleep()超时后会继续执行, wait()须要notify()或notifyAll()唤醒;(3)sleep()不放弃对象锁,wait()会释放对象锁.
答: nodify()唤醒一个等待锁的线程, 由JVM决定是哪一个, nodifyAll()会通知全部等待锁的线程, 这些线程会争夺对象锁, 抢到的持有锁并继续执行, 其余的继续等待通知.
答: run()定义了线程执行的逻辑, start()方法用来启动线程.run()能够执行屡次.
答:
java.util.concurrent.Executors
方法下的几个静态建立线程池的方法,newFixedThreadPool(), newWorkStealingPool(),newSingleThreadExecutor(),newCachedThreadPool(),newSingleThreadScheduledExecutor(),newScheduledThreadPool()
public ThreadPoolExecutor(int corePoolSize, //核心线程数 int maximumPoolSize, //最大线程数, 当核心线程达到最大, 且队列满以后新入队的元素将开启更多线程, 总数最大不超过这个值 long keepAliveTime, // 线程存活时间, 指核心线程外的线程 TimeUnit unit, //时间单位 BlockingQueue<Runnable> workQueue //线程队列, 只有经过execute()方法调用的才会进入 ) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
newSingleThreadExecutor()
corePoolSize=1 , maximumPoolSize=1 , keepAliveTime=0 , workQueue使用LinkedBlockingQueue
newCachedThreadPool()
corePoolSize=0 , maximumPoolSize=Integer.MAX_VALUE , keepAliveTime=60 , TimeUnit=SECONDS , workQueue使用 SynchronousQueue ; 同步队列, 来即处理
newFixedThreadPool()
corePoolSize=maximumPoolSize=传入的参数 , keepAliveTime=0 , workQueue使用 LinkedBlockingQueue ;
newWorkStealingPool()
使用ForkJoinPool
实例, 并行队列,since 1.8
答: RUNNING(正在运行), STOP(不接受新任务, 再也不处理队列中的任务, 中断正在执行的线程), SHUTDOWN(不接受新任务, 但继续队列中的任务),TIDYING(全部任务均销毁了, workcount=0, 线程池转为此状态时会启动钩子方法terminated),TERMINATED(teminated()执行结束)
RUNNING -> SHUTDOWN :
shutdown()
, 或者隐式在finalize()
(RUNNING or SHUTDOWN) -> STOP :shutdownNow()
SHUTDOWN -> TIDYING : 队列和池均为空
STOP -> TIDYING : 池为空
TIDYING -> TERMINATED :terminated()
执行完
答: execute()方法用来执行
Runnable
接口类型的任务, submit()能够接受Runnable
也能够接受Callable
.
答: 使用锁
Lock
, 以及线程安全的类java.util.concurrent
, 代码同步关键字synchronized
等
答: synchronized是重量级锁, 若是资源被占用则当前线程进入阻塞队列, 清空缓存, 但不少时候刚刚挂起资源就释放了, 也就是说资源征用其实没有想象的那么频繁, 通常资源总会被同一个线程占用. 从1.6开始对其优化, 分为三种级别, 偏向锁,轻量级锁,重量级锁. 参考Java并发——Synchronized关键字和锁升级,详细分析偏向锁和轻量级锁的升级
偏向锁, 在对象头设置标识位和threadid, 偏向锁不会主动释放锁, 若是同一线程再次获取, 则比较threadid, 相同则无需cas加锁解锁, 若是不一致则查看对象头中保存的线程是否存活, 不存活则当前线程设置为偏向锁, 存活则代表有多于一个线程竞争锁, 此时锁可能升级为轻量级锁.
轻量级锁: 对于多个线程争用锁, 但线程持有锁时间不长的情景. 使用自旋必定次数来等待锁释放. 从而减小阻塞.
重量级锁: 对于自旋必定时间的线程, 超出限制后锁可能膨胀为重量级锁, 由操做系统调度管理. 重量级锁会阻塞线程, 防止CPU空转.
锁升级后再也不降级, 但偏向锁能够被重置为无锁状态.
答: 多个线程间互相等待对方释放本身所需资源(锁)的状况, 循环等待致使线程阻塞.
答: (1). 顺序执行; (2).检测死锁; (3). 减少锁粒度; (4).设置锁超时时间
答: 线程本地变量, 为每一个线程提供独立的变量副本, 本线程修改的值不会影响到其余线程的同名变量.
如数据库连接, session
答: synchronized能够修饰代码块, 方法, 静态方法. 这三种状况实现不一样. 对于代码块, 在块的开始和结束的地方虚拟机分别会插入monitorenter和monitorexit指令, 必须成对出现, monitor是实现锁的机制, 一个线程持有monitor, 其余线程就被挂起了. 对于方法, 虚拟机会在方法表中为其设置access_flag状态.
答: synchronized用于方法和代码块, volatile用于变量. valatile解决了变量在多线程环境下的可见性.synchronized解决了对临界资源的访问控制. volatile并不能保证原子性,synchronized能保证原子性; volatile不阻塞线程,synchronized会致使线程阻塞.volatile会防止指令重排.volatile效率更高.
答: synchronized是关键字, 封装了java对锁的实现. Lock是jdk提供的, 包含一系列预约义的类. synchronized内部实现加锁解锁, 异常时释放锁, Lock须要代码中调用相关方法, 不解锁就不会释放. Lock抽象可让程序员对锁有更精细控制以及定制操做.
答: 参看54, 另外,ReentrantLock能够设置超时, 可被中断.
答: 其内部实现不是简单的使用synchronized,而是一个更为高效的方式CAS (compare and swap) + volatile和native方法,从而避免了synchronized的高开销,执行效率大为提高. 核心是
UnSafe
类, 直接经过操做系统API操做. atomic并不是无阻塞, 而是阻塞不在程序,线程级别, 而是在底层上面.
答: 反射是在程序运行时可以动态获取和操做对象的能力.
答: 序列化就是将对象转化为可以进行网络传输或存储的数据格式. java的序列化须要对象实现serializable接口.
保存对象文件; 网络传输; 远程方法调用.
答: 动态代理是在运行时生成代理类. 好比原生的基于接口的代理或CGLib实现Spring 的AOP机制.
答: 基于java原生的接口方式的代理; 使用CGLib库实现的基于类继承的代理.
答: 克隆是Java对原型模式的实现, 克隆省去了new的开销, 同时能够保存对象的状态.
答: (1).实现Cloneable接口并重写clone()方法; (2).使用序列化反序列化实现克隆
答: 这就得区分java对象在内存中的存储方式, 浅拷贝对于值类型,直接复制内容, 但对于引用类型, 只是复制了一份对真实对象的引用. 深拷贝就是须要将引用类型的变量内容也同时复制, 从而生成一个彻底不一样的对象.
答: jsp:java server page. 与asp,asp.net等同样,是java生态的服务端动态页面技术. servlet : server端小程序, 重在控制.事实上jsp就是在servlet基础上实现的, 但更着重前端页面.
答: request: 封装客户端请求, 能够接收参数; respose: 封装服务端响应; pageContext: 页面上下文; session: 会话信息; application: 应用级别的对象; out: 服务端输出流对象; config: 配置对象; page: JSP页面; exception: 封装页面抛出的异常.
答: (1).page : 本页面相关的对象; (2). session: 表明一次会话做用域内的; (3).application: 应用程序级别的, 做用域最广, 全局, (4).request : 一次请求内
答: session是服务端对象, cookie是存储在客户端浏览器特定目录的; session理论上没有容量限制,cookie不能太大, 也有个数限制; session更为安全, cookie有伪造的风险;session通常存储在内存, 或内存数据库中, 也能够存在关系数据库;
答: 用户初次登录网站后, 服务端会给客户端响应添加session id, 以后客户端每次请求均带有这个id, 服务端获取后经过此id找到对应的session对象.
答: 能够, session id 可能以请求参数或header之类的方式请求到客户端.
答: (不了解struts) 下面是搜索到的答案.
(1). 拦截级别, struts是类级别的拦截, spring是方法级别拦截;(2). 数据独立性: Spring mvc 方法之间基本独立, 独享request,response数据, 请求经过参数获取, 返回ModelMap,方法之间不共享变量;struts2方法之间也独立, 但全部action变量是共享的, 编码和阅读代码不友好.(3). 拦截机制, spring mvc 用的独立的aop方式;struts2有本身框架的拦截机制;(4)对ajax的支持: spring mvc 更方便, 使用@ResponseBody注解可实现; struts2须要插件或自定义;
答: PreparedStatement, 关键字或符号转义, 过滤特殊字符
答: XSS: 跨站脚本攻击, 是攻击者在web页面植入js代码, 等页面被浏览后代码执行从而达到攻击目的. 避免方法是对用户输入的内容进行编码, 过滤js等关键字.
答: 跨站请求伪造, 是攻击者盗用别人身份并发送恶意请求进行欺骗的手段. 避免方法是: 验证请求来源, 只接受同源的请求; 添加验证码; 使用token验证.
答: throw 是抛出异常的关键字, 后面是一个异常实例;throws是表示方法可能会抛出的异常, 后面是异常的类名, 用来方法前面上面.
答: final修饰变量, 方法, 类. 被修饰的代表不能被修改,重写或继承;finally是异常处理块, 其中的代码必然执行;finalize是类的析构方法, 通常不需本身定义.
答: try与其余两者之一必须成对存在.
答: 会执行, finally中的代码无论什么状况下, 必然会执行.
答: NullPointerException, ClassNotFoundException,IOExcption,IndexOutOfBoundsException,ClassCastException,NoSuchMethodException...
答: 3XX 是跳转响应码. 301时永久跳转, 对SEO友好, 302时临时跳转,可能会被拦截.
答: forward会带有原页面请求, redirect至关于从新打开一个页面; redirect的地址栏会变, forward则不会; forward效率要高点.
答: 都是传输层协议.
tcp面向连接, udp非连接便可发送数据; tcp提供可靠的数据传输,udp没法保证; tcp面向字节流, udp面向报文; tcp传输效率低, udp传输快;
答: 两次握手的话, 服务端发出确认信号, 但客户端未必会响应, 而此时链接以及创建, 但客户端并非真的须要服务端, 这就形成了资源浪费.
答: 发送端: 发送端须要等缓冲区满才发送, 形成粘包; 接受端: 接受端不及时接受缓冲区的包, 形成多个包接受.
答: 物理层, 数据链路层,网络层, 传输层,会话层,表现层,应用层.
答: post比get更安全; get有限制, post没限制; get地址栏显式, 可收藏;post不行.get 可缓存;
答: 反向代理如njinx; 服务端设置CORS为*; 单个接口设置@CrossOrigin; 使用jsonp;
答: Json with Padding, 利用scrpt的src能够访问不一样源的特性, 加载远程返回的js函数来执行.
答: 单例模式: 类本身管理自身的实例化, 节省资源; 工厂模式, 观察者模式;代理模式, 模版方法, 策略模式, 生成器模式.
答: 抽象工厂用来生成一系列产品族, 工厂方法指示生成一种产品, 他们都支持增长产品. 简单工厂更像是一种编程习惯, 用来管理产品的生成.
答: Spring流行,生态完善, 特别是spring boot, spring cload简化了开发和部署; spring 是各类框架的粘合剂; spring将设计尽可能延迟, 开发者能够尽可能晚地作决定, 好比修改配置便可替换某个类; Spring 容器更容易管理依赖; aop技术能够抽离切面; spring提供事务支持.
答: 面向切面编程, 经过java原生或cglib加强来实现. aop能够将一部分如事务, 日志, 异常等统一的功能抽离, 统一维护.
答: ioc是控制反转, 是将原来类自身管理它依赖的方式替换为由容器统一管理, 这就将依赖作到很大程度解耦.
答: spring core 提供ioc; spring context ; dao, aop, web, mvc等.
答: setter注入, 构造函数注入. 另外还有编程注入, 但这方式太原始, 并不仅是spring的, 只能说它只是达成注入的一种方式.
答: 默认的bean是单例的, spring 并不能保证bean的线程安全.
spring的bean大可能是无状态的, 因此大多状况下不存在线程不安全的问题. 但若是须要保持有状态的bean, 就必须使用其余做业域了. 如prototype.
答: 六种: singleton, prototype, session, request,application, websocket. 后面四种仅仅在web环境下.
答: 四种方式, no 不使用, 经过ref等方式来完成; bytype 经过类型, byname 经过名字, constructor: 相似bytype只是应用于构造函数参数. bytype和byname能够组装数组.
答: 使用@Transaction的声明式事务, 或编码实现.
答: 事务隔离机制: 未提交读,提交读,可重复读, 序列化; spring的事务隔离与数据库相同, 但还有个默认方式, 即便用数据库使用的隔离级别.
答: 请求-> DispatcherServlet-> handlermaping-> handler(controller action)-> modelAndView-> viewResolver->view
答: DispatcherServlet, HandlerMapping, ViewResolver, Controller, ModelAndView,LocaleResolver等.
答: 请求映射, 就是将http请求的特定url到特定的handler上.
答: 自动装配, 使用该注解的字段,方法,构造函数自动完成依赖注入. 减小了配置.
答: Spring boot 是为了简化Spring开发的, 简化了spring程序的初始搭建和开发部署, 提供了开箱即用的开发体验和一套非功能性组件, 能够作到几乎没有配置.
答: 配置简单; 独立运行,有内置的web容器; 自动配置,极少的xml配置文件; 快速搭建和部署;
答: bootstrap.XX 和 application.XX
答: properties 和 yml 两种格式的配置文件, yml语法更严格, 能够减小错误, 但缺少自由度, yml配置看起来有层次, 两种方式各有优劣. yml不支持@PropertySource. 能够经过实现
PropertySourceFactory
接口来实现.
答: 开发时使用devtools, 配置中添加spring.devtools.restart.enabled=true; idea中配置自动编译.
答: jpa时规范, java persistence api. hibernate是框架, 基于jpa实现.
答: 基于spring boot 实现的一系列框架的合集. 提供了分布式系统中非功能性的基础实现, 如配置注册中心, 路由, 熔断, 负载均衡, 监控等. 只须要极少配置便可使用.
答: 当分布式架构中的服务单元发生故障时或其余缘由如流量过载等缘由时, 断路器会根据设置的阀值断定正常服务或快速返回错误, 这样能够防止服务长时间的等待, 从而防止故障蔓延.
答: Eureka, Feign, Ribbon, Hystrix,Zuul.
12、Hibernate
答: hibernate是对jdbc的封装, 简化了访问数据库的重复代码; hibernate提供ORM实现, 简化了DAO层的编码; 具备数据库可移植性; 缓存提高了效率.
答: Object Relation Mapping, 是将关系数据库的表或视图等映射为程序中的对象. 这样能够简化开发.
答: hibernate.show_SQL=true
答: 原生SQL, HQL, 条件查询Criteria.
答: 能够, 但final的不能被继承, 也就不能使用代理模式实现延迟关联来提高性能了.
答: 对象和值, Integer能够为null.
答: 读取解析配置文件, 建立SessionFacotry, 打开Session, 建立事务, 操做, 提交事务, 关闭Session, 关闭SessionFactory.
答: load()支持延迟加载, get()不支持; 没有OID指定的对象, get()返回null, load返回代理对象.
答: 分为一级缓存和二级缓存; 一级缓存是Session缓存, Session做用域有效. 二级缓存是application缓存, 全局有效, 并支持三方缓存.
答: 临时状态(不受Session管理), 持久化状态(持久化到数据库中的), 游离状态(Session关闭后的对象).
答: getCurrentSession() 绑定当前线程, openSession()不会; getCurrentSession()受事务管理, openSession()须要手动管理事务.
答: 是的, hibernate使用反射实例化实体. 没有无参构造会报异常.
答: #{} 是预编译处理, ${}是字符替换. 使用#{}时, Mybatis会将其替换为?, 这样能够防止SQL注入, 保证程序安全.
答: 物理分页和逻辑分页. RowBounds使用逻辑分页. 分页插件PageHelper或自定义分页使用物理分页.
答: 也不是, jdbc有个Fetch Size的设置, 只有当须要更多数据时, 它才会从数据库查询更多数据.
答: 逻辑分页时在内存中进行, 一次查询出不少数据, 在内存进行分页, 这种方式占用大量内存, 可能致使内存溢出; 物理分页是直接查询出所需数据, 在数据库分页, 这种分页按需返回数据, 但数据库压力可能较大.
答: 支持. 能够设置lazyLoadingEnable=true启用.
延迟加载是在使用实例的时候, 好比调用对象a.getName(), 若是发现a为null, 则加载a并返回. 延迟加载就是在使用时才去触发查询的SQL.
答: 一级缓存是基于PerpetualCache的HashMap本地缓存, 生命周期与SQLSession相同, 可能会出现脏数据, 在session关闭或清空后缓存失效. 默认开启. 二级缓存也是基于PerpetualCache的HashMap本地缓存, 不一样的是做用域为Mapper级别, 能够在多个Session间共享, 能够自定义缓存如使用EhCache. 使用二级缓存须要类实现Serializable接口.
查询顺序: 二级缓存 --> 一级缓存 --> 数据库.
更新策略: 同一做用域下发生更新后, 默认该做用域下的select缓存均clear.
答: Mybatis更灵活, 能够本身写sql; 可移植性hibernate要好; 二级缓存hibernate能够自行更换;
答: 有三种基本执行器: (1). SimpleExecutor: 每执行一次update或select就开启一个statement对象, 用完当即关闭statement对象; (2). ReuseExecutor: 执行update,select, 以sql语句做为key查找statement对象, 存在则使用, 不存在则建立, 用完存在Map以备后面再用. (3). BatchExecutor: 执行update, 将多个sql添加到批处理中, 等待统一执行, 它缓存了多个statement对象, 等待统一处理.
答: 拦截器实现, 拦截sql, 而后重写为对应的分页sql.
答: (1). 插件要实现interceptor接口
public interface Interceptor{ // 拦截的适合要执行的逻辑 Object intercept(Invocation invocation) throws Throwable; // 用于封装目标对象, 该方法返回对象自己或其代理, 可决定是否要进行拦截进而决定要返回什么样的对象. Object plugin(Object target); // 在MyBatis进行配置插件的适合能够配置自定义相关属性, 接口实现对象的参数配置. void setProperties(Properties properties); }
(2). 插件应用的目标对象: Executor, StatementHandler,ParameterHandler, ResultSetHandler.
(3). 实现示例:
@Intercepts({ @Signature(type=Executor.class, method="query",args={ MappedStatement.class,Object.class,RowBounds.class, ResultHandler.class }) }) public class TestInterceptor implements Interceptor{ public Object intercept(Invocation invocation) throws Throwable{ Object target = invocation.getTarget();// 被代理对象 Method method = invocation.getMethod(); // 代理方法 Object[] args = invocation.getArgs(); //方法参数 ///....... 方法执行前的代码 Object result = invocation.proceed(); ///........方法执行后的代码 return result; } public Object plugin(Object target){ return Plugin.wrap(target,this); } }
答: rabbitmq是目前比较流行的amqp消息队列, 适合使用的场景有: 1. 系统削峰填谷; 2. 延迟队列; 3. 系统解耦.
答: 问题问的是构成rabbitmq的系统角色, rabbitmq是生产者/消费者模式的结构. 所以分为生产者: 消息的建立方, 负责发送消息到消息服务器; 消费者: 消息接收方, 用于处理数据; 中介代理: 即rabbitmq自己, 用来接受消息并按必定数据格式存储, 并为消费者提供消息.
答:
答: 相似数据库的实例, 每一个vhost有本身的一套队列,交换机和绑定以及本身的权限机制.
答: 客户端经过tcp连接到RabbitMQ服务器, 一旦经过了认证, 客户端和服务器之间就建立了一条amqp信道, 信道是建立在真实tcp上的虚拟连接, amqp命令是经过信道发出去的, 每一个信道都有一个惟一的id, 不论发布仍是订阅均经过此信道完成.
答: 提供了事务支持; 能够将channel设置为confirm模式.
答: 把消息持久化到磁盘, 保证重启数据不丢失; 集群中至少有个物理磁盘, 保证消息落入磁盘.
答: 队列queue必须设置持久化durable为true; 消息推送投递模式必须设置持久化, deliveryMode=2; 消息已经到达持久化交换机; 消息已经到达持久化队列.
答: 持久化须要将数据写入磁盘, 跟其余磁盘io的系统同样,这样会下降服务器吞吐量, 下降性能.
答: direct, 默认方式, 发送消息给订阅方, 对于多个订阅方采用轮询的方式进行; headers, 性能较差, 此类型几乎用不到; fanout, 分发模式, 分发给全部订阅者; topic: 匹配订阅, 可使用正则匹配到消息队列, 能匹配到的都能接收到.
答: 有两种方式: 一是消息过时后进入死信交换机, 再由交换机转发到延迟消费队列, 实现延迟功能; 二是使用delayed-message-exchange插件实现延迟功能.
答: 高可用, 高容量
答: 磁盘节点, 可持久化数据; 内存节点, 高效.
答: 各节点之间用"-link"链接; 各节点使用erlang coolie值必须相同, 至关于密钥, 用于认证; 整个集群中必须包含一个磁盘节点.
答: 不是, 缘由有二: 存储空间和性能.
答: 集群能够保持运行, 只是不能修改任何东西了. (1)不能建立队列;(2)不能建立交换器;(3)不能建立绑定;(4)不能添加用户;(5)不能更改权限;(6)不能添加删除节点.
答: 须要先关闭内存节点, 再关闭磁盘节点, 不然可能会致使数据丢失.
答: 不能够, kafka使用zookeeper协调管理kafka的节点服务器.
答: 两种: 按过时时间保留, 按存储消息大小保留.
答: 两个规则为或的关系, 只要一个知足要求即清除数据.
答: 傻逼问题, 傻逼答案... cpu, io, 网络
答: 集群节点最好不要超过7个, 节点越多消息复制须要的时间越长, 整个群组的吞吐量就越低. 集群数为2N+1个较好. 超过一半故障集群就不能用了, 单数容错更高一点.
答: zookeeper是分布式协调调度RPC框架, 它为分布式应用提供一致性服务, 包括配置注册中心,域名服务,分布式锁等.
数据采用树形方式, 能够支持临时和永久, 有序和无序两种方式的任意组合.
答: 事件监听, 文件存储; 适用的场景包括: 发布订阅,配置注册中心, 命名服务, leader选举, 负载均衡, 分布式队列, 分布式锁等.
答: 单实例部署, 集群部署.
答: Zookeeper 的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫作Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步之后,恢复模式就结束了。状态同步保证了leader和Server具备相同的系统状态。
为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。全部的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
答: 分布式环境中, 有些业务逻辑只须要在集群中的某台服务器执行, 这样能够保证这些事务逻辑的原子性, 同时也保证只在一台服务器执行,这样能够提升性能, 减小重复计算.等执行完成后结果被其余的节点共享.
答: 可使用, 通常集群的机器节点数为2N+1, 只要有大于一半的服务器在线便可正常提供服务, 三台宕机一台依然有两台可用.
答: zookeeper采用注册/监听方式, 使用
Watcher
来实现对节点和路径事件的监控.
十7、MySql
答: 1. 原子性, 每一个字段都只表示一个属性; 2. 每一个字段均依赖于主键, 也就是一张表只表示一个对象; 3. 属性不能传递依赖,也就是有传递依赖的地方要拆分为不一样表;
答: Innodb和myIASM两种执行引擎的方式不一样, Innodb会在内存中存储表中的自增id, myiasm是在表中保留, 所以innodb重启后会丢失最大id, 而会从现有表中计算因此结果为6, myiasm为8.
答: select version()
答: ACID是数据库事务的特性, A是atomicity, 即原子性, 原子性保证一个事务以一个总体逻辑执行, 要么成功, 要么失败, 执行完成后不会发生中间状态; C是consistency, 即一致性, 即事务执行开始和结束后, 数据的完整性没有遭到破坏; I是Isolation, 隔离性, 多个并发的事务对数据来讲不会由于交叉执行而致使数据不一致, 数据库存在四个隔离级别, 分别解决不一样程度的数据隔离;D 是 durability, 是持久性, 事务执行后对数据修改时永久的, 数据保持完成.
答: char是固定长度的, varchar是可变长度的,char可能会存在空间浪费的状况, varchar使用的空间是n+1, 其中有一个char单位用来保存长度, 性能方法, char的性能要高一点,
答: 大小不一样, float是4字节的, double是8字节的.
答: 内链接是两个表能匹配的数据, 左链接和右链接则分别以左表或右边为主, 展现出左表或右表的数据, 对于匹配不到的, 右表或左表展现为null.
答: mysql或其余数据库的索引大多采用B+树数据结构, B+树自己就是有序结构, 能够达到二分法的性能.
答: explain 查询语句, 查看执行计划
答: MySql.ini配置文件有默认的事务隔离配置, transaction-isolution=REPEATABLE-READ.
事务有四个级别的隔离方式, 分别为:
脏读: 一个事务能读取另外一个事务未提交的数据; 不可重复读: 一个事务内屡次读取同一个数据;幻读: 同一事务屡次读取的数据不一致.
答: InnoDB: 提供了对数据库的acid事务支持, 并提供行级锁和外键约束, 它设计的目标就是处理大数据容量的数据库系统. 它会在启动时创建缓冲池, 用来缓存数据和索引. 但不支持全文索引, 启动也比较慢. 不会保存行数, 但并发环境下的读取效率很高.
MyIASM: 默认引擎, 不提供事务支持, 不支持行锁和外键. 因此变动时会锁表,效率比较低. 但其保存了行数, 读多余写的操做可使用此搜索引擎.
答: 行锁是在数据变动时仅会在当前行加锁, 其余行仍是能够访问的, 锁的级别较小, 不容易发生阻塞.表锁是变动时会对整个表加锁, 性能低下, 不利于并发.
答: 乐观锁是默认没有别的进程修改数据, 仅在提交更新时断定数据版本号是否与修改前一致; 悲观锁是默认认为数据在同一时间可能被其余进程修改, 所以先锁定数据, 修改后释放锁.
答: show processlist, explain, 查看日志
答: 索引, 合适的查询语句, 表分区, 正确的搜索引擎
答: redis是一种nosql数据库, 是用C实现的, 具备高性能, 单线程, 支持持久化, 支持集群的高可用内存数据库.
用来作数据库, 缓存, 消息中间件
答: 复制, 集群, 持久化, 事务, 分布式锁,LUA脚本, LRU
答: (1) 持久化的支持, 数据可靠性: redis能够作持久化, memcache是内存没法持久化; (2) 底层实现方面: redis利用单线程, memcache多线程, 可使用多核CPU; (3). 数据结构方面: redis支持较多的数据结构, memcache仅仅是k-v结构;(4). 数据大小, 小于100kredis比较快, 大于100k,memcache较快, 但redis支持最大512M的数据, memcache最大为1M; (5)应用场景: memcache适合读多写少, 或数据比较大的对象,redis适合读写都不少, 比较复杂的数据结构.
答: redis是基于内存操做的, CPU不会存在瓶颈, 既然CPU不是瓶颈, 单线程又很容易实现, 那么redis天然就选择用单线程了.
对于多个CPU的服务器, 能够开多个redis实例来提升服务器资源使用率. 注意: redis4.0 开始可能会有条件地在某些操做时使用多线程.
183.什么是缓存穿透?怎么解决?
答: String, Set, ZSet, List, Hash
不常见的有: Bitmaps,Hyperloglogs 和地理空间(Geospatial)索引半径查询
答: Jedis, Redisson等, 官方推荐Redisson
答: jedis是对原生redis的简单封装, redisson是官方推荐的客户端程序, 除了基本的命令, 还有更丰富的数据结构以及锁的实现.
答: 更新时先删除缓存, 设置数据过时时间, 异步更新数据.
答: aof, rdb
aof是写日志方式, 是按指定策略经过日志恢复数据的方式.
rdb是快照方式, 支持同步(save)和异步方式(bgsave)保存数据. save会阻塞服务, 直到保存完成. bgsave不阻塞, 但可能运行期间的数据会发生丢失.
答: setNX命令, 返回1表示成功, 0位失败.
答: 执行时间超过锁超时时间时会致使并发问题.
答: 尽可能使用Redis的散列表, 把相关信息放在散列表里面, 而不是各个字段单独存储, 这样能够有效减小内存.
答: 六种, 分别是volatile-ttl, 过时的数据集中清除超时的;volatile-lru,过时的里面清除不经常使用的数据;volatile-random,过时的数据里面随机清除; allkeys-random, allkeys-lru, 与上面同样, 只是范围为全部的数据集.no-enviction,禁止淘汰
答: redis是在进行持久化的时候会致使性能问题. 写内存快照会阻塞主线程, 当快照较大时会较长时间的致使服务暂停, 全部主服务器最好不要写快照. 主从复制的性能问题, 复制的速度和稳定性. 主从最好在一个局域网内.
答:
总的来讲就是类加载器会将java代码转化为字节码, 运行时区把字节码加载到内存, 为了调用操做系统功能, 执行引擎须要调用本地方法.
答:
程序计数器, 堆, 栈, 方法区
栈又分为虚拟机栈和本地方法栈.
方法区和堆是全部线程共享的, 其余为线程隔离.
程序计数器是记录程序执行顺序的一小块内存区域, 存储程序执行指令的行号信息, 存储虚拟机字节码指令地址, 本地方法时计数值为空, 内存模型中不会发生 OutOfMemoryException
.
虚拟机栈是方法执行时同时建立的, 用于支持方法执行和调用的数据结构,栈帧用于存储局部变量表、操做数栈、动态连接、方法返回地址和一些额外的附加信息.编译程序代码时,栈帧中须要多大的局部变量表、多深的操做数栈都已经彻底肯定了,而且写入了方法表的 Code 属性之中.
1. 局部变量表: 一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量, 局部变量表的容量以变量槽(Slot)为最小单位. 局部变量表所需的内存空间在编译期间完成分配; 2. 操做数栈: 最大深度也是在编译的时候就肯定了.32 位数据类型所占的栈容量为 1,64 位数据类型所占的栈容量为 2。当一个方法开始执行时,它的操做栈是空的,在方法的执行过程当中,会有各类字节码指令(好比:加操做、赋值元算等)向操做栈中写入和提取内容,也就是入栈和出栈操做。 3. 动态链接: 每一个栈帧都包含一个指向运行时常量池(在方法区中,后面介绍)中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程当中的动态链接。Class 文件的常量池中存在有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用,一部分会在类加载阶段或第一次使用的时候转化为直接引用(如 final、static 域等),称为静态解析,另外一部分将在每一次的运行期间转化为直接引用,这部分称为动态链接。 4. 方法返回地址: 方法返回时可能须要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。通常来讲,方法正常退出时,调用者的 PC 计数器的值就能够做为返回地址,栈帧中极可能保存了这个计数器值,而方法异常退出时,返回地址是要经过异常处理器来肯定的,栈帧中通常不会保存这部分信息
本地方法栈为使用到的本地操做系统(Native)方法服务。
它用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。运行时常量池是方法区的一部分.
堆是存储对象信息的内存区域, 是 GC 主要工做区域, 虚拟机将堆又分为 Eden, Survive, Old, Perm 等区块, 通常新生代分配为 1/4 到 1/3, 默认 3/8. 新生代的 Eden ,Survive 默认比例为 8:1:1 .
直接内存:直接从操做系统中分配,所以不受 Java 堆大小的限制,可是会受到本机总内存的大小及处理器寻址空间的限制. NIO 机制能够直接从操做系统中分配直接内存,即在堆外分配内存.
答:
堆是JVM分配的一块共享内存区域, 占用了虚拟机内存的绝大多数空间, 堆存储的是对象的实例或数组, 这里也是GC的主要区域. 栈是各线程独立的内存区域, 在编译时就已经肯定大小, 栈存储方法执行时的相关信息, 包含局部变量表,操做数栈, 动态链接, 方法返回等信息.
答:
Queue
和 Stack
都是数据结构, Queue
支持 FIFO, Stack
支持 FILO. Queue
是接口, 继承了 Collection
. Stack
则实现了 Vector
, 方法是线程安全的.
答:
Java 的类加载机制支持四种类加载器, customer -> app -> ext -> bootstrap bootstrap 是最顶级加载器, 用于加载 rt.jar , ext 次之, 加载javahome/lib下的其余类. 双亲委派模型就是在类加载时当前加载器首先委托给上层加载器进行加载, 上层加载器没法加载才是本加载器进行加载, 这样设计是基于安全性考虑, 这样能够避免本加载器加载覆盖上层加载器的一些类, 好比 String
基于此模式必然会优先经过 bootstrap 加载.
答:
加载 -> 链接(验证 -> 准备 -> 解析) -> 初始化
链接: 分为三步
初始化: 静态变量赋值, 静态代码块执行
答:
经过垃圾对象标记算法, 分为两种:
JVM会起一个线程从全部的GC Roots开始往下遍历,当遍历完以后若是发现有一些对象不可到达,那么就认为这些对象已经没有用了,须要被回收。四种引用类型: 强引用、软引用、弱引用和虚引用.
答:
强引用、软引用、弱引用和虚引用. 引用强度依次下降. 强引用不会被GC, 软引用在内存不够的状况下会被回收; 弱引用只要开始GC, 就会被回收. 虚引用最弱, 必须和 ReferenceQueue 队列一块儿使用.
答:
复制算法: 新生代使用的算法, 分为Eden,和两个 Survive 区域, GC时将Survive 1的对象所有复制到2, 同时Eden中非垃圾对象也复制到2.
标记-整理: Old区域的回收, 首先标记出垃圾对象, 而后将对象整理存放在内存的一端, 这样内存不会有碎片
标记-清除: 跟标记-整理相似, 不过GC时只清除垃圾对象. 可能致使内存不连续.
分代收集: 根据对象生命周期, 上述算法混合使用
答:
Serial, Serial Old, ParNew , Parallel Scavenge, Serial Old, Parallel Old, CMS, G1
具体参看面试题 关于垃圾收集的部分.
答:
CMS 追求最低停顿时间, 使用标记-清除算法. 通常与parnew 等收集器协同工做. 分四步: 1.初始标记, 2.并发标记, 3.重复标记, 4.并发清除. 1,3会致使停顿.
答:
新生代: Serial, ParNew, parallow scavenge (追求可控的吞吐量)
老生代: CMS (追求最低停顿时间) , Serial Old , parallow Old
G1 为分代收集.
答:
新生代和老生代采用不一样的收集算法, 新生代采用复制算法, 老生代采用标记-整理算法.
答:
jps, jinfo, jstat, jstack, jmap,jconsole,jvisualvm
参看这篇文章
答:
参看面试题 线上应用的 JVM 参数有哪些.