2018年 最新Java面试题

温馨提示:本文适合初,中级水平。如果是面试高级需要多了解一下多线程高并发以及底层原理源码等知识。

AOP与IOC的概念(即spring的核心)

a) IOC:Spring是开源框架,使用框架可以使我们减少工作量,提高工作效率并且它是分层结构,即相对应的层处理对应的业务逻辑,减少代码的耦合度。而spring的核心是IOC控制反转和AOP面向切面编程。IOC控制反转主要强调的是程序之间的关系是由容器控制的,容器控制对象,控制了对外部资源的获取。而反转即为,在传统的编程中都是由我们创建对象获取依赖对象,而在IOC中是容器帮我们创建对象并注入依赖对象,正是容器帮我们查找和注入对象,对象是被获取,所以叫反转。

b) AOP:面向切面编程,主要是管理系统层的业务,比如日志,权限,事物等。AOP是将封装好的对象剖开,找出其中对多个对象产生影响的公共行为,并将其封装为一个可重用的模块,这个模块被命名为切面(aspect),切面将那些与业务逻辑无关,却被业务模块共同调用的逻辑提取并封装起来,减少了系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。

温馨提示:可以研究一下AOP切面编程方法,以及切入点等。

设计模式知道有哪些?
单例模式
优点:
只有一个实例,减少了内存开支;
可以避免对系统资源的多重占用;
可以在系统中设置全局的访问点,优化和共享资源访问;
缺点:
没有接口,扩展困难;
对测试开发不利;
应用场景:
要求生成唯一序列号的场景;
需要一个共享访问点;
创建一个对象需要消耗过多的资源时
需要定义大量的静态常量和静态方法时(也可直接声明为static的方式);

工厂方法模式
优点:
良好的封装性,代码结构清晰;
扩展非常好;
屏蔽产品类;
应用场景:
是new一个对象的替代品;
需要灵活的,可扩展的框架时;
使用在测试驱动开发的框架下;

抽象工厂模式
优点:
封装性;
产品族内部的约束为非公开状态;
缺点:
产品族扩展困难;

温馨提示:面试的时候一般会问项目中那里用到了这些模式,请举例说一下实现了什么功能等。

cookie和 session的区别:
 --1.cookie数据存放在客户的浏览器,session数据放在服务器上。
 --2.cookie不是很安全,别人可以分析存放本地的cookie并行cookie欺骗考虑到安全应当使用session。
 --3.session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能,应当使用cookie。
 --4.单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
 --5.个人建议:将登陆信息存放为session 其他信息如果需要保留,可以放在cookie中

final和finally和finalize的区别:
final是全局变量声明的时候使用,意思是这个变量不可被修改,不可被override,一般用于声明常量,或者系统设置的值。
finally是在try-catch-finally块中配套使用,作用是,不管代码执行了try还是catch,最后一定会执行finally里面的代码
finalize是召唤垃圾收集器的命令,使用后,系统就安排一次垃圾回收
但是不是立即执行,执行的时间点是无法确定的。
没有特别的要求的话一般不需要使用finalize,交给gc自己管理就好。

JAVA虚拟机了解吗?

JAVA的JVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method)堆区:
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身
栈区:
1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
方法区:
1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。

温馨提示:笔试的时候可能会让你画Java虚拟机机构图。这个就不是单单的JVM的内存图了。

下图是JAVA虚拟机的结构图:

2018年 最新Java面试题_第1张图片
java既然存在gc线程,为什么还存在内存泄漏?
  答:无论哪种语言的内存分配方式,都需要返回分配内存的真实地址,Java中对象通过new关键字或反射创建对象,存放在堆中,所有对象的回收都是由Java虚拟机通过垃圾回收机制完成的,GC会检测长时间没有使用的对象进行回收,但是像一些静态字段、静态引用类、数据库的连接、网络连接等,若没有正确处理,还是会造成内存泄漏。

java内存泄漏的根本原因是?
  答:内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。
如何避免内存泄漏?
  答:明确引用变量的生命周期,是方法内部的局部变量,还是类实例变量,与类实例生命周期相同的要声明为实例变量。
要避免这种情况下的内存泄露,要求我们以C/C++ 的内存管理思维来管理自己分配的内存。第一,是在声明对象引用之前,明确内存对象的有效作用域。在一个函数内有效的内存对象,应该声明为 local 变量,与类实例生命周期相同的要声明为实例变量……以此类推。第二,在内存对象不再需要时,记得手动将其引用置空。

hashMap 原理?为什么是线程不安全的,底层是用什么实现的?。
   答:在JDK1.6,JDK1.7中,HashMap采用位桶(类似数组)+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,HashMap采用位桶+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。

在java jdk8中对HashMap的源码进行了优化,在jdk7中,HashMap处理“碰撞”的时候,都是采用链表来存储,当碰撞的结点很多时,查询时间是O(n)。
在jdk8中,HashMap处理“碰撞”增加了红黑树这种数据结构,当碰撞结点较少时,采用链表存储,当较大时(>8个),采用红黑树
(特点是查询时间是O(logn))存储(有一个阀值控制,大于阀值(8个),将链表存储转换成红黑树存储)

hashmap底层实现方法不是同步的,
HashMap在并发执行put操作时会引起死循环(两个put的key发生了碰撞(hash值一样),那么根据HashMap的实现,这两个key会添加到数组的同一个位置,这样最终就会发生其中一个线程的put的数据被覆盖),导致CPU利用率接近100%。因为多线程会导致HashMap的Node链表形成环形数据结构,一旦形成环形数据结构,
Node的next节点永远不为空,就会在获取Node时产生死循环。(发生多个线程同时对Node数组进行扩容,都在重新计算元素位置以及复制数据,但是最终只有一个线程扩容后的数组会赋给table,也就是说其他线程的都会丢失,并且各自线程put的数据也丢失)

解决hash冲突的办法?
Java中hashmap的解决办法就是采用的链地址法。


HashMap,Hashtable,ConcurrentHashMap和synchronized Map的原理和区别。
   答:HashMap不是线程安全的;Hashtable线程安全,但效率低,因为是Hashtable是使用synchronized的,所有线程竞争同一把锁;而ConcurrentHashMap不仅线程安全而且效率高,因为它包含一个segment数组,将数据分段存储,给每一段数据配一把锁,也就是所谓的锁分段技术。


JDK1.8在JDK1.7的基础上针对一个链上数据过多(即拉链过长的情况)导致性能下降,增加了红黑树来进行优化。即当链表超过8时,链表就转换为红黑树,利用红黑树快速增删改查的特点提高HashMap的性能,其中会用到红黑树的插入、删除、查找等算法。

ArrayList和 LinkedList的区别?
   ArrayList实现了List接口,它是以数组的方式来实现的,数组的特性是可以使用索引的方式来快速定位对象的位置,因此对于快速的随机取得对象的需求,使用ArrayList实现执行效率上会比较好. 
   LinkedList是采用链表的方式来实现List接口的,它本身有自己特定的方法,如: addFirst(),addLast(),getFirst(),removeFirst()等. 由于是采用链表实现的,因此在进行insert和remove动作时在效率上要比ArrayList要好得多!适合用来实现Stack(堆栈)与Queue(队列),前者先进后出,后者是先进先出.

ArrayList

      优点:适合随机读取的时候,读取速度快,可以一步get(index)。

  缺点:添加值很慢——一方面,添加数据在array中间的时候,需要移动后面的数;另一方面,当长度大于初始长度的时候,每添加一个数,都会需要扩容。

LinkedList:双向链表

  优点:添加,删除很快——添加在list中间也只需要更改指针;长度不固定。
实现栈和队列方面,LinkedList要优于ArrayList。
 

理论经典:TCP协议的3次握手与4次挥手过程详解。传输的报文格式是什么?
       (A)URG:紧急指针(urgent pointer)有效。
       (B)ACK:确认序号有效。
       (C)PSH:接收方应该尽快将这个报文交给应用层。
       (D)RST:重置连接。
       (E)SYN:发起一个新连接。
       (F)FIN:释放一个连接。

(1)第一次握手:
Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。

(2)第二次握手:
Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。

(3)第三次握手:
Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

SYN攻击:

在三次握手过程中,Server发送SYN-ACK之后,收到Client的ACK之前的TCP连接称为半连接(half-open connect),此时Server处于SYN_RCVD状态,当收到ACK后,Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server回复确认包,并等待Client的确认,由于源地址是不存在的,因此,Server需要不断重发直至超时,这些伪造的SYN包将产时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击,检测SYN攻击的方式非常简单,即当Server上有大量半连接状态且源IP地址是随机的,则可以断定遭到SYN攻击了,使用如下命令可以让之现行:

#netstat -nap | grep SYN_RECV

第一次挥手:
Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。
第二次挥手:
Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。
第三次挥手:
Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。
第四次挥手:
Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。


请写出JDBC连接数据库的代码。
//1.加载驱动
Calss.forName("com.mysql.jdbc.driver");
//创建数据库连接对象
Connection conn = DriverManager.getConnection(url,user,password)


Threadlocal的作用?
    ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下, ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

ThreadLocal和Synchonized都用于解决多线程并发访问题。但是ThreadLocal与synchronized有本质的区别:
    synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。

什么情况下索引失效?

1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:select id from t where num is null

3.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。

4.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如:

select id from t where num=10 or Name = 'admin'


高数据并发下的数据安全: 
1、悲观锁,锁住数据库。但是这种不太好,在高并发下,会因为请求太多被阻塞而使得系统陷入异常。
2、队列的思想。将请求都放入队列中,先进的先出嘛。问题是,当高并发的时候,一瞬间队列空间会被撑爆。或者说,因为队列太大,最终处理时间还是会变长。这两种情况都会导致系统异常。
3、乐观锁:比较适合。当数据来访问的时候,都可以修改数据,但是给加上version,只有在version最前的时候,最终才能够执行成功,其他的用户回滚。

尽量将请求拦截在系统上游

读多写少的常用多使用缓存

String、StringBuffer与StringBuilder之间区别?
   答:String的值是不可变的,每次操作都会产生新的String对象。在线程安全上,StringBuilder是线程不安全的,效率高,是可变的字符串序列。而StringBuffer是线程安全的,效率低,是可变的字符串序列,有一定的缓冲区,当字符串大小没有超过容量时,不会产生新的对象。
String:适用于少量的字符串操作的情况,
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况,
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况。

  
线程的生命周期?

新建 :从新建一个线程对象到程序start() 这个线程之间的状态,都是新建状态;
就绪 :线程对象调用start()方法后,就处于就绪状态,等到JVM里的线程调度器的调度;
运行 :就绪状态下的线程在获取CPU资源后就可以执行run(),此时的线程便处于运行状态,运行状态的线程可变为就绪、阻塞及死亡三种状态。
等待/阻塞/睡眠 :在一个线程执行了sleep(睡眠)、suspend(挂起)等方法后会失去所占有的资源,从而进入阻塞状态,在睡眠结束后可重新进入就绪状态。
终止 :run()方法完成后或发生其他终止条件时就会切换到终止状态。

数据库的优化?
    如:数据库集群,分表分库,读写分离,添加索引,适当添加冗余字段,尽量单表操作,少使用*查询等等。


请写出一个考虑并发安全的单例?
public class MySingleton {
    
    private static MySingleton instance = null;
    
    private MySingleton(){}
    
    public synchronized  static MySingleton getInstance() {
        if(instance == null){//懒汉式
            instance = new MySingleton();
        }
        return instance;
    }
}

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

以下是spring Cloud微服务的相关问题。面试的时候可以在网上找一下相关视频看看,会spring Cloud的会有优势。现在新项目一般都采用spring Cloud开发。以前开发的项目一般是分布式的采用Dubbo。但很小的项目一般也用不上,哈哈!
什么是微服务?
   答:微服务架构是一种架构模式或者说是一种架构风格,它提倡将单一应用程序划分为一组小的服务,每个服务运行在独立的自己
进程中,服务之间相互协调、配合,为用户提供最终价值。
     或者说微服务化的核心就是将传统的一站式应用,根据业拆分成一个一个的服务,彻底地去耦合,每一个微服务提供单一业务功能的服务,
一个服务做一件事,从技术角度看就是一种小而独立的处理过程,类似进程概念,能够自行单独启动或者销毁,拥有自己独立的数据库。

spring Cloud和Dubbo有哪些区别?
    答:本质区别是通信机制不一样。Dubbo 基于RPC远程过程调用,spring Cloud是基于HTTP的restful apl(REST API)调用。

微服务的优缺点分别是什么?说一下你在项目中遇到的坑?
  答:Martin Fowler对 微服务架构 的描述中,虽然该架构相较于单体架构有模块化解耦、可独立部署、技术多样性等诸多优点,
但是由于分布式环境下解耦,也带出了不少测试与运维复杂度。
   优点:每个服务足够内聚,足够小,代码容易理解这样能聚焦一个指定的业务功能或者业务需求
   开发简单、开发效率提高、一个服务可能就是专一的只干一件事
   微服务能够被小团队单独开发,这个小团队是2-5人左右的开发人员组成
   微服务是松藕合的,是有功能意义的服务,无论是在开发阶段或者部署阶段都是独立的
   微服务能使用不同的语言开发
   易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如:jenkins,Hudson,bamboo
   微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值
   微服务允许你利用融合最新技术
   微服务只是业务逻辑代码,不会和HTML,CSS或者其他界面组件混合
   每个微服务都有自己的存储能力,可以有自己的数据库。也可以有统一的数据库
    缺点:开发人员要处理分布式系统的复杂性
    多服务运维难度,随着服务的增加,运维的压力也在增大
    系统部署依赖
    服务间通信成本
    数据一致性
    系统集成测试
    性能监控。。。。

传统的ACID分别是什么?
   答:A(Atomicity)原子性 C(Consistency)一致性 I(Isolation)独立性 D(Durability)持久性
CAP是什么?
   答:C(Consistency)强一致性 A(Availability)可用性 P(Partition tolerance)分区容错性

eureka和zookeeper都可以提供服务注册与发现的功能,请说说两个的区别?
   答:著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性)、A(可用性)、P(分区容错性)。
由于分区容错性P在分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡。
   因此Zookeeper保证的是CP,Eureka则是AP。

   Zookeeper保证的是CP:当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。
也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩下节点会重新
进行leader选举。问题在于,选举leader的时间太长,30-120s,且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署坏境下,
因网络问题使得zk集群失去master节点是较大的概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致注册长期不可用是不能容忍的。
  Eureka保证AP:设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点工作,剩余的节点依然可以提供注册和查询服务。
而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),
只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,eureka还有一种自我保护机制,如果在15反正内超过85%的节点都没有正常的心跳,那么
Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
  1.Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务
  2.Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)
  3.当网络稳定时,当前实例新的注册信息会被同步到其它节点中

  因此,Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。

Ribbon是什么?怎么实现的?
   答:Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。对ConfigBean使用注解@LoadBalanced实现的,有轮询算法,随机算法,时间加权算法,重试算法等等。默认是轮询算法。需要修改的话在ConfigBean中选择相应的算法。一般使用RetryRule算法。因为服务正常的情况先先按RoundRobinRule(轮询策略),如果获取服务失败则在指定时间内会进行重试,获取可用的服务。也可以自己定义策略。在主启动类上加@RibbonClient(name="微服务名",configuration=策略自定义类名.class),策略自定义类不能放在@ComponentScan扫描当前包下以及子包下(不能主启动类包下面)。

Feign是一个声明式的Web服务客户端,使得编写Web服务客户端变得非常容易。只需要创建一个接口,然后在上面添加注解即可。
Feign可以与Eureka和Ribbon组合使用以支持负载均衡。

hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等待,hystrix能够保证在一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,以提供分布式系统的弹性。
hystrix能够进行服务降级,服务熔断,服务限流,接近实时的监控。

什么是服务熔断?什么是服务降级?
    答:服务熔断一般是指软件系统中,由于某些原因使得服务出现了过载现象,为防止造成整个系统故障,从而采用的一种保护措施,所以很多地方把熔断亦称为过载保护。
    触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
    管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始)

服务监控有什么作用?
   答:使用hystrixDashboard技术快速发现故障实例和高压力实例。

使用zuul技术对访问真实路径进行保护,使用虚地址访问。

引入新技术的步骤?
  答:第一步,pom.xml中添加依赖坐标。第二步,在主启动类添加启动注解@EnableXXX.如@EnableEurekaClient

如何搭建微服务架构?
  答:整套开发技术栈以SpringCloud为主,单个微服务模块以SpringMVC+SpringBoot/Spring+Mybatis组合进行开发
      前端层,页面H5 +thymeleaf/样式CSS3+Bootstrap/前端框架JQuery+Node|vue等
      负载层,前端访问通过Http或者Https协议到达服务端的LB,可以是F5等硬件做负载均衡,还可以自行部署LVS+Keepalived等(前期量小可以直接使用Nginx)
      网关层,请求通过LB后,会到达整个微服务体系的网关层Zuul(Gateway),内嵌Ribbon做客户端负载均衡,Hystrix做熔断降级等
      服务注册,采用Eureka来做服务治理,Zuul会从Eureka集群获取已发布的微服务访问地址,然后根据配置把请求代理到相应的微服务去
      docker容器,所有的微服务模块都部署在Docker容器里面,而且前后端服务完全分开,各自独立部署后前端微服务调用后端微服务,后端微服务之间会有相互调用
      服务调用,微服务模块间调用都采用标准的Http/Https+REST+JSON的方式,调用技术采用Feign+HttpClient+Ribbon+Hystrix
      统一配置,每个微服务模块会跟Eureka集群、配置中心(SpringCloudConfig)等进行交互
      第3方框架,每个微服务模块根据实现的需要,通常还需要使用一些第三方框架,比如常用的有:缓存服务(Redis)、图片服务(FastDFS)、搜索服务(ElasticSearch)、安全管理(shiro)等等
      Mysql数据库,可以按照微服务模块进行拆分,统一访问公共库或者单独自己库,可以单独构建Mysql集群或者分库分表MyCat等。

如果你是湖南的欢迎加入湖南人在深圳-Java群:557651502

你可能感兴趣的:(java)