【最新】经典面试100问,附答案

本文由公众号「Java旅途」整理,设计到的内容由java基础、数据库、SSM框架、redis、消息队列、spring boot、spring cloud、git及一些前端知识。整理时间为2019-11-19,首发于微信公众号「Java旅途」,关注微信公众号「Java旅途」,回复面试领取该pdf版资料。公众号二维码如下:

2019年java面试经典100问,进入BAT不是梦。如果该pdf帮助到您,请您传阅给您的小伙伴,一起复习,共同做一个offer收割机,文章目录如下:

一、java基础

1、面向对象的特征有哪些方面? 【基础】

答:面向对象的特征主要有以下几个方面:

1)抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象。

2)继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。

3)封装:封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。

4)多态性:多态性是指允许不同类的对象对同一消息作出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。

2、int 和Integer 有什么区别? 【基础】

答:Java 提供两种不同的类型:引用类型和原始类型(或内置类型);

int 是java 的原始数据类型,Integer 是java 为int 提供的封装类。

Java 为每个原始类型提供了封装类:

原始类型: boolean,char,byte,short,int,long,float,double

封装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double引用类型和原始类型的行为完全不同,并且它们具有不同的语义。引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为null,而原始类型实例变量的缺省值与它们的类型有关。

3、Math.round(11.5) 等于多少? Math.round(-11.5)等于多少? 【基础】

答:Math.round(11.5)12 Math.round(-11.5)-11 round 方法返回与参数最接近的长整数,参数加1/2 后求其floor。

4、编程题: 用最有效率的方法算出2 乘以8 等於几? 【基础】

答: 2 << 3。

5、数组有没有 length()方法?String 有没有 length()方法?【基础】

答:数组没有 length()方法,有 length 的属性。String 有 length()方法。JavaScript 中,获得字符串的长度是通过 length 属性得到的,这一点容易和 Java 混淆。

6、构造器(constructor)是否可被重写(override)?【基础】

答:构造器不能被继承,因此不能被重写,但可以被重载。

7、是否可以继承String 类? 【基础】

答:String 类是final 类,故不可以继承。

8、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 【基础】

答:是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。

9、String 和StringBuffer 的区别?【基础】

答:JAVA 平台提供了两个类:String 和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String 类提供了数值不可改变的字符串。而这个StringBuffer 类提供的字符串进行修改。当你知道字符数据要改变的时候你就可以使用StringBuffer。典型地,你可以使用StringBuffers 来动态构造字符数据。

10、String, StringBuffer StringBuilder 的区别。【基础】

答:String 的长度是不可变的;StringBuffer 的长度是可变的,如果你对字符串中的内容经常进行操作,特别是内容要修改时,那么使用StringBuffer.如果最后需要String,那么使用StringBuffer 的toString()方法,线程安全;StringBuilder 是从JDK 5 开始,为StringBuffer 该类补充了一个单个线程使用的等价类;通常应该优先使用StringBuilder 类,因为它支持所有相同的操作,但由于它不执行同步,所以速度更快,线程不安全。

11、重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?【基础】

答:方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求。

12、描述一下 JVM 加载 class 文件的原理机制?【中等】

答:JVM 中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java 中的类加载器是一个重要的 Java 运行时系统组件,它负责在运行时查找和装入类文件中的类。

由于 Java 的跨平台性,经过编译的 Java 源程序并不是一个可执行程序,而是一个或多个类文件。当 Java 程序需要使用某个类时,JVM 会确保这个类已经被加载、连接(验证、准备和解析)和初始化。类的加载是指把类的.class 文件中的数据读入到内存中,通常是创建一个字节数组读入.class 文件,然后产生与所加载类对应的 Class 对象。加载完成后,Class 对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后 JVM 对类进行初始化,包括:

1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;

2)如果类中存在初始化语句,就依次执行这些初始化语句。

从 Java 2(JDK 1.2)开始,类加载过程采取了双亲委托机制(PDM)。PDM 更好的保证了 Java 平台的安全性,在该机制中,JVM 自带的 Bootstrap 是根加载器,其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。

13、interface可以有方法的实现吗?【中等】

答:jdk1.8以后有方法的实现,用default修饰。

14、是否可以从一个static 方法内部发出对非static 方法的调用?【基础】

答:不可以,如果其中包含对象的method(),不能保证对象初始化。

15、GC 是什么? 为什么要有GC? 【基础】

答:GC 是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java 提供的GC 功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java 语言没有提供释放已分配内存的显示操作方法。Java 程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc()

16、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?【基础】

答:对于GC 来说,当程序员创建对象时,GC 就开始监控这个对象的地址、大小以及使用情况。通常,GC 采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC 确定一些对象为"不可达"时,GC 就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC 运行,但是Java 语言规范并不保证GC 一定会执行。

17、一个“.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?【基础】

答:可以;必须只有一个类名与文件名相同。

18、Java 中的 final 关键字有哪些用法?【基础】

答:(1)修饰类:表示该类不能被继承;(2)修饰方法:表示方法不能被重写;(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。

19、编码转换:怎样将GB2312 编码的字符串转换为ISO-8859-1 编码的字符串?【基础】

答:示例代码如下:

String s1 = "你好";

String s2 = new String(s1.getBytes("GB2312"), "ISO-8859-1");

20、error 和exception 有什么区别? 【基础】

答:error 表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的情况;exception 表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。

21、try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?【基础】

答:会执行,在方法返回调用者前执行。

注意:在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,就会返回修改后的值。显然,在finally中返回或者修改返回值会对程序造成很大的困扰,C#中直接用编译错误的方式来阻止程序员干这种龌龊的事情,Java中也可以通过提升编译器的语法检查级别来产生警告或错误,Eclipse中可以在如图所示的地方进行设置,强烈建议将此项设置为编译错误。

22、List,Set,Map 是否继承自Collection 接口?【基础】

答:List,Set 是;Map 不是。

23、说出ArrayList,Vector, LinkedList 的存储性能和特性?【基础】

答:ArrayList 和Vector 都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector 由于使用了synchronized 方法(线程安全),通常性能上较ArrayList 差,而LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。

24、HashMap 和Hashtable 的区别? 【基础】

答:二者都实现了Map 接口,是将惟一键映射到特定的值上;主要区别在于:

1)HashMap 没有排序,允许一个null 键和多个null 值,而Hashtable 不允许;

2)HashMap 把Hashtable 的contains 方法去掉了,改成containsvalue 和containsKey,因为contains 方法容易让人引起误解;

3)Hashtable 继承自Dictionary 类,HashMap 是Java1.2 引进的Map 接口的实现;

4)Hashtable 的方法是Synchronize 的,而HashMap 不是,在多个线程访问Hashtable 时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。Hashtable 和HashMap 采用的hash/rehash 算法大致一样,所以性能不会有很大的差异。

25、Arraylist 与Vector 区别?【基础】

答:就ArrayList 与Vector 主要从二方面来说:

1)同步性:Vector 是线程安全的(同步),而ArrayList 是线程序不安全的;

2)数据增长:当需要增长时,Vector 默认增长一倍,而ArrayList 却是一半。

26、List、Map、Set 三个接口,存取元素时,各有什么特点?【基础】

答:List 以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存key-value 值,value 可多值。

27、sleep() 和wait() 有什么区别? 【基础】

答:sleep 是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep 不会释放对象锁。wait 是Object 类的方法,对此对象调用wait 方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify 方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。

28、当一个线程进入一个对象的一个synchronized 方法后,其它线程是否可进入此对象的其它方法? 【基础】

答:其它线程只能访问该对象的其它非同步方法,同步方法则不能进入。

29、多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么? 【基础】

答:多线程有两种实现方法,分别是继承Thread 类与实现Runnable 接口,同步的实现方面有两种,分别是synchronized,wait 与notify。

30、当一个线程进入一个对象的 synchronized 方法 A 之后,其它线程是否可进入此对象的 synchronized 方法 B?【中等】

答:不能。其它线程只能访问该对象的非同步方法,同步方法则不能进入。因为非静态方法上的 synchronized 修饰符要求执行方法时要获得对象的锁,如果已经进入 A 方法说明对象锁已经被取走,那么试图进入 B 方法的线程就只能在等锁池(注意不是等待池哦)中等待对象的锁

31、简述synchronized 和java.util.concurrent.locks.Lock 的异同?【中等】

答:主要相同点:Lock 能完成synchronized 所实现的所有功能;主要不同点:Lock 有比synchronized 更精确的线程语义和更好的性能。synchronized 会自动释放锁,而Lock 一定要求程序员手工释放,并且必须在finally 从句中释放。

32、编写多线程程序有几种实现方式?【中等】

答:Java 5 以前实现多线程有两种实现方法:一种是继承 Thread 类;另一种是实现 Runnable 接口。两种方式都要通过重写 run()方法来定义线程的行为,推荐使用后者,因为 Java 中的继承是单继承,一个类有一个父类,如果继承了 Thread 类就无法再继承其他类了,显然使用 Runnable 接口更为灵活。

补充:Java 5 以后创建线程还有第三种方式:实现 Callable 接口,该接口中的 call 方法可以在线程执行结束时产生一个返回值,代码如下所示:

import java.util.ArrayList;

import java.util.List;
import java.util.concurrent.Callable;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import java.util.concurrent.Future;


class MyTask implements Callable<Integer> {

    private int upperBounds;

    public MyTask(int upperBounds) {
    
    	this.upperBounds = upperBounds;
    }

    @Override

    public Integer call() throws Exception {
  	  int sum = 0;

        for(int i = 1; i <= upperBounds; i++) {

        	sum += i;
        }

    return sum;

    }

}

class Test {

    public static void main(String[] args) throws Exception { 
    List<Future<Integer>> list = new ArrayList<>(); 
    ExecutorService service = Executors.newFixedThreadPool(10);

    for(int i = 0; i < 10; i++) {

    	list.add(service.submit(new MyTask((int) (Math.random() * 100))));
    }

    int sum = 0;

    for(Future<Integer> future : list) {

    	//while(!future.isDone()) ; 
    	sum += future.get();

    }

    System.out.println(sum);

    }
}

33、Java 中如何实现序列化,有什么意义?【中等】

答:序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决对象流读写操作时可能引发的问题(如果不进行序列化可能会存在数据乱序的问题)。要实现序列化,需要让一个类实现 Serializable 接口,该接口是一个标识性接口,标注该类对象是可被序列化的,然后使用一个输出流来构造一个对象输出流并通过 writeObject(Object)方法就可以将实现对象写出(即保存其状态);如果需要反序列化则可以用一个输入流建立对象输入流,然后通过 readObject 方法从流中读取对象。

二、数据库

34、阐述 JDBC 操作数据库的步骤。【基础】

答:下面的代码以连接本机的 Oracle 数据库为例,演示 JDBC 操作数据库的步骤。

//加载驱动。
Class.forName("oracle.jdbc.driver.OracleDriver");

//创建连接。
Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger");

//创建语句。
PreparedStatement ps = con.prepareStatement("select * from emp where sal between ? and ?"); ps.setInt(1, 1000);

ps.setInt(2, 3000);

//执行语句。
ResultSet rs = ps.executeQuery();

//处理结果。
while(rs.next()) {
	System.out.println(rs.getInt("empno") + " - " + rs.getString("ename"));
}

//关闭资源。
finally {
    if(con != null) {
        try {
        	con.close();
        } catch (SQLException e) {
        	e.printStackTrace();
        }
    }
}

提示:关闭外部资源的顺序应该和打开的顺序相反,也就是说先关闭 ResultSet、再关闭Statement、在关闭 Connection。上面的代码只关闭了 Connection(连接),虽然通常情况下在关闭连接时,连接上创建的语句和打开的游标也会关闭,但不能保证总是如此,因此应该按照刚才说的顺序分别关闭。此外,第一步加载驱动在 JDBC 4.0 中是可以省略的(自动从类路径中加载驱动),但是我们建议保留。

35、使用 JDBC 操作数据库时,如何提升读取数据的性能?如何提升更新数据的性能?【中等】

答:要提升读取数据的性能,可以指定通过结果集(ResultSet)对象的 setFetchSize()方法指定每次抓取的记录数(典型的空间换时间策略);要提升更新数据的性能可以使用 PreparedStatement 语句构建批处理,将若干 SQL 语句置于一个批处理中执行。

36、在进行数据库编程时,连接池有什么作用?【基础】

答:由于创建连接和释放连接都有很大的开销(尤其是数据库服务器不在本地时,每次建立连接都需要进行 TCP 的三次握手,释放连接需要进行 TCP 四次握手,造成的开销是不可忽视的),为了提升系统访问数据库的性能,可以事先创建若干连接置于连接池中,需要时直接从连接池获取,使用结束时归还连接池而不必关闭连接,从而避免频繁创建和释放连接所造成的开销,这是典型的用空间换取时间的策略(浪费了空间存储连接,但节省了创建和释放连接的时间)。池化技术在 Java 开发中是很常见的,在使用线程时创建线程池的道理与此相同。基于 Java 的开源数据库连接池主要有:C3P0、Proxool、DBCP、BoneCP、Druid 等。

37、事务的ACID是指什么?【基础】

答:

  • 原子性(Atomic):事务中各项操作,要么全做要么全不做,任何一项操作的失败都会导致整个事务的失败;

  • 一致性(Consistent):事务结束后系统状态是一致的;

  • 隔离性(Isolated):并发执行的事务彼此无法看到对方的中间状态;

  • 持久性(Durable):事务完成后所做的改动都会被持久化,即使发生灾难性的失败。通过日志和同步备份可以在故障发生后重建数据。

38、谈谈脏读、幻读和不可重复读?【中等】

脏读(Dirty Read):A 事务读取 B 事务尚未提交的数据并在此基础上操作,而 B 事务执行回滚,那么 A 读取到的数据就是脏数据。

时间转账事务 A 取款事务 B
T1 开始事务
T2 开始事务
T3 查询账户余额为 1000 元
T4 取出 500 元余额修改为 500
T5 查询账户余额为 500 元(脏读)
T6 撤销事务余额恢复为 1000 元
T7 汇入 100 元把余额修改为 600 元
T8 提交事务

不可重复读(Unrepeatable Read):事务 A 重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务 B 修改过了。

时间转账事务 A 取款事务 B
T1 开始事务
T2 开始事务
T3 查询账户余额为 1000 元
T4 查询账户余额为 1000 元
T5 取出 100 元修改余额为 900 元
T6 提交事务
T7 查询账户余额为 900 元(不可重复读)

幻读(Phantom Read):事务 A 重新执行一个查询,返回一系列符合查询条件的行,发现其中插入了被事务 B 提交的行。

时间统计金额事务 A 转账事务 B
T1 开始事务
T2 开始事务
T3 统计总存款为 10000 元
T4 新增一个存款账户存入 100 元
T5 提交事务
T6 再次统计总存款为 10100 元(幻读)

第 1 类丢失更新:事务 A 撤销时,把已经提交的事务 B 的更新数据覆盖了。

时间取款事务 A 转账事务 B

时间取款事务 A 转账事务 B
T1 开始事务
T2 开始事务
T3 查询账户余额为 1000 元
T4 查询账户余额为 1000 元
T5 汇入 100 元修改余额为 1100 元
T6 提交事务
T7 取出 100 元将余额修改为 900 元
T8 撤销事务
T9 余额恢复为 1000 元(丢失更新)
第 2 类丢失更新:事务 A 覆盖事务 B 已经提交的数据,造成事务 B 所做的操作丢失。
时间转账事务 A 取款事务 B
T1 开始事务
T2 开始事务
T3 查询账户余额为 1000 元
T4 查询账户余额为 1000 元
T5 取出 100 元将余额修改为 900 元
T6 提交事务
T7 汇入 100 元将余额修改为 1100 元
T8 提交事务
T9 查询账户余额为 1100 元(丢失更新)

数据并发访问所产生的问题,在有些场景下可能是允许的,但是有些场景下可能就是致命的,数据库通常会通过锁机制来解决数据并发访问问题,按锁定对象不同可以分为表级锁和行级锁;按并发事务锁定关系可以分为共享锁和独占锁,具体的内容大家可以自行查阅资料进行了解。直接使用锁是非常麻烦的,为此数据库为用户提供了自动锁机制,只要用户指定会话的事务隔离级别,数据库就会通过分析 SQL 语句然后为事务访问的资源加上合适的锁,此外,数据库还会维护这些锁通过各种手段提高系统的性能,这些对用户来说都是透明的(就是说你不用理解,事实上我确实也不知道)。

ANSI/ISO SQL 92 标准定义了4 个等级的事务隔离级别,如下表所示:

隔离级别 脏读 不可重复读幻读 第一类丢失更新第二类丢失更新
READ UNCOMMITED 允许 允许 允许 不允许 允许
READ COMMITTED 不允许 允许 允许 不允许 允许
REPEATABLE READ 不允许 不允许 允许 不允许 不允许
SERIALIZABLE 不允许 不允许 不允许 不允许 不允许

需要说明的是,事务隔离级别和数据访问的并发性是对立的,事务隔离级别越高并发性就越差。所以要根据具体的应用来确定合适的事务隔离级别,这个世界没有万能的原则。

39、JDBC中如何进行事务处理?【中等】

答:Connection 提供了事务处理的方法,通过调用setAutoCommit(false)可以设置手动提交事务;当事务完成后用 commit()显式提交事务;如果在事务处理过程中发生异常则通过 rollback()进行事务回滚。除此之外,从 JDBC 3.0 中还引入了 Savepoint(保存点)的概念,允许通过代码设置保存点并让事务回滚到指定的保存点。

40、获得一个类的类对象有哪些方式?【基础】

答:

  • 方法 1:类型.class,例如:String.class

  • 方法 2:对象.getClass(),例如:"hello".getClass()

  • 方法 3:Class.forName(),例如:Class.forName("java.lang.String")

41、JSP 有哪些内置对象?作用分别是什么?【基础】

答:JSP 有 9 个内置对象:

  • request:封装客户端的请求,其中包含来自 GET 或 POST 请求的参数;

  • response:封装服务器对客户端的响应;

  • pageContext:通过该对象可以获取其他对象;

  • session:封装用户会话的对象;

  • application:封装服务器运行环境的对象;

  • out:输出服务器响应的输出流对象;

  • config:Web 应用的配置对象;

  • page:JSP 页面本身(相当于 Java 程序中的 this);

  • exception:封装页面抛出异常的对象。

42、get 和 post 请求的区别?【基础】

答:①get 请求用来从服务器上获得资源,而 post 是用来向服务器提交数据;

②get 将表单中数据按照 name=value 的形式,添加到 action 所指向的 URL 后面,并且两者使用"?"连接,而各个变量之间使用"&"连接;post 是将表单中的数据放在 HTTP 协议的请求头或消息体中,传递到 action 所指向 URL;

③get 传输的数据要受到 URL 长度限制(1024 字节);而 post 可以传输大量的数据,上传文件通常要使用 post 方式;

④使用 get 时参数会显示在地址栏上,如果这些数据不是敏感数据,那么可以使用 get;对于敏感数据还是应用使用 post;

⑤get 使用 MIME 类型 application/x-www-form-urlencoded 的 URL 编码(也叫百分号编码)

文本的格式传递参数,保证被传送的参数由遵循规范的文本组成,例如一个空格的编码是"%20"。

43、讲解 JSP 中的四种作用域。【基础】

答:JSP 中的四种作用域包括 page、request、session 和 application,具体来说:

  • page 代表与一个页面相关的对象和属性。

  • request 代表与 Web 客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个 Web 组件;需要在页面显示的临时数据可以置于此作用域。

  • session 代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应该放在用户自己的 session 中。

  • application 代表与整个 Web 应用程序相关的对象和属性,它实质上是跨越整个 Web 应用程序,包括多个页面、请求和会话的一个全局作用域。

三、SSM框架

44、MyBatis 中使用#和$书写占位符有什么区别?【中等】

答:#将传入的数据都当成一个字符串,会对传入的数据自动加上引号;$将传入的数据直接显示生成在 SQL 中。注意:使用$占位符可能会导致 SQL 注射攻击,能用#的地方就不要使用$,写 order by 子句的时候应该用$而不是#。

45、解释一下 MyBatis 中命名空间(namespace)的作用。【中等】

答:在大型项目中,可能存在大量的 SQL 语句,这时候为每个 SQL 语句起一个唯一的标识(ID)就变得并不容易了。为了解决这个问题,在 MyBatis 中,可以为每个映射文件起一个唯一的命名空间,这样定义在这个映射文件中的每个 SQL 语句就成了定义在这个命名空间中的一个 ID。只要我们能够保证每个命名空间中这个 ID 是唯一的,即使在不同映射文件中的语句 ID 相同,也不会再产生冲突了。

46、什么是 IoC 和 DI?DI 是如何实现的?【中等】

答:IoC 叫控制反转,是 Inversion of Control 的缩写,DI(Dependency Injection)叫依赖注入,是对 IoC 更简单的诠释。控制反转是把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的"控制反转"就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。IoC 体现了好莱坞原则 - "Don’t call me, we will call you"。依赖注入的基本原则是应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由容器负责,查找资源的逻辑应该从应用组件的代码中抽取出来,交给容器来完成。DI 是对 IoC 更准确的描述,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。

47、解释一下什么叫 AOP(面向切面编程)?【基础】

答:AOP(Aspect-Oriented Programming)指一种程序设计范型,该范型以一种称为切面(aspect)的语言构造为基础,切面是一种新的模块化机制,用来描述分散在对象、类或方法中的横切关注点(crosscutting concern)。

48、你是如何理解"横切关注"这个概念的?【中等】

答:"横切关注"是会影响到整个应用程序的关注功能,它跟正常的业务逻辑是正交的,没有必然的联系,但是几乎所有的业务逻辑都会涉及到这些关注功能。通常,事务、日志、安全性等关注就是应用中的横切关注功能。

49、你如何理解 AOP 中的连接点(Joinpoint)、切点(Pointcut)、增强(Advice)、引介(Introduction)、织入(Weaving)、切面(Aspect)这些概念?【基础】

答:a. 连接点(Joinpoint):程序执行的某个特定位置(如:某个方法调用前、调用后,方法抛出异常后)。一个类或一段程序代码拥有一些具有边界性质的特定点,这些代码中的特定点就是连接点。Spring 仅支持方法的连接点。

b. 切点(Pointcut):如果连接点相当于数据中的记录,那么切点相当于查询条件,一个切点可以匹配多个连接点。Spring AOP 的规则解析引擎负责解析切点所设定的查询条件,找到对应的连接点。

c. 增强(Advice):增强是织入到目标类连接点上的一段程序代码。Spring 提供的增强接口都是带方位名的,如:BeforeAdvice、AfterReturningAdvice、ThrowsAdvice 等。很多资料上将增强译为“通知”,这明显是个词不达意的翻译,让很多程序员困惑了许久。

说明: Advice 在国内的很多书面资料中都被翻译成"通知",但是很显然这个翻译无法表达其本质,有少量的读物上将这个词翻译为"增强",这个翻译是对 Advice 较为准确的诠释,我们通过 AOP 将横切关注功能加到原有的业务逻辑上,这就是对原有业务逻辑的一种增强,这种增强可以是前置增强、后置增强、返回后增强、抛异常时增强和包围型增强。

d. 引介(Introduction):引介是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过引介功能,可以动态的未该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。

e. 织入(Weaving):织入是将增强添加到目标类具体连接点上的过程,AOP 有三种织入方式:①编译期织入:需要特殊的 Java 编译期(例如 AspectJ 的 ajc);②装载期织入:要求使用特殊的类加载器,在装载类的时候对类进行增强;③运行时织入:在运行时为目标类生成代理实现增强。Spring 采用了动态代理的方式实现了运行时织入,而 AspectJ 采用了编译期织入和装载期织入的方式。

f. 切面(Aspect):切面是由切点和增强(引介)组成的,它包括了对横切关注功能的定义,也包括了对连接点的定义。

50、Spring 支持的事务管理类型有哪些?你在项目中使用哪种方式?【中等】

答:Spring 支持编程式事务管理和声明式事务管理。许多 Spring 框架的用户选择声明式事务管理,因为这种方式和应用程序的关联较少,因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理,尽管在灵活性方面它弱于编程式事务管理,因为编程式事务允许你通过代码控制业务。

51、Spring MVC的工作原理是怎样的?【基础】

答:SpringMVC工作原理图如下:

① 客户端的所有请求都交给前端控制器 DispatcherServlet 来处理,它会负责调用系统的其他模块来真正处理用户的请求。

② DispatcherServlet 收到请求后,将根据请求的信息(包括 URL、HTTP 协议方法、请求头、请求参数、Cookie 等)以及 HandlerMapping 的配置找到处理该请求的 Handler(任何一个对象都可以作为请求的 Handler)。

③在这个地方 Spring 会通过 HandlerAdapter 对该处理器进行封装。

④ HandlerAdapter 是一个适配器,它用统一的接口对各种 Handler 中的方法进行调用。

⑤ Handler 完成对用户请求的处理后,会返回一个 ModelAndView 对象给 DispatcherServlet, ModelAndView 顾名思义,包含了数据模型以及相应的视图的信息。

⑥ ModelAndView 的视图是逻辑视图,DispatcherServlet 还要借助 ViewResolver 完成从逻辑视图到真实视图对象的解析工作。

⑦ 当得到真正的视图对象后,DispatcherServlet 会利用视图对象对模型数据进行渲染。

⑧ 客户端得到响应,可能是一个普通的 HTML 页面,也可以是 XML 或 JSON 字符串,还可以是一张图片或者一个 PDF 文件。

52、什么是 XSS 攻击?【困难】

答: XSS(Cross Site Script,跨站脚本攻击)是向网页中注入恶意脚本在用户浏览网页时在用户浏览器中执行恶意脚本的攻击方式。跨站脚本攻击分有两种形式:反射型攻击(诱使用户点击一个嵌入恶意脚本的链接以达到攻击的目标,目前有很多攻击者利用论坛、微博发布含有恶意脚本的 URL 就属于这种方式)和持久型攻击(将恶意脚本提交到被攻击网站的数据库中,用户浏览网页时,恶意脚本从数据库中被加载到页面执行,QQ 邮箱的早期版本就曾经被利用作为持久型跨站脚本攻击的平台)。XSS 虽然不是什么新鲜玩意,但是攻击的手法却不断翻新,防范 XSS 主要有两方面:消毒(对危险字符进行转义)和 HttpOnly (防范 XSS 攻击者窃取 Cookie 数据)。

53、SQL 注入攻击?【困难】

答: SQL 注入攻击是注入攻击最常见的形式(此外还有 OS 注入攻击(Struts 2 的高危漏洞就是通过 OGNL 实施 OS 注入攻击导致的)),当服务器使用请求参数构造 SQL 语句时,恶意的 SQL 被嵌入到 SQL 中交给数据库执行。SQL 注入攻击需要攻击者对数据库结构有所了解才能进行,攻击者想要获得表结构有多种方式:(1)如果使用开源系统搭建网站,数据库结构也是公开的(目前有很多现成的系统可以直接搭建论坛,电商网站,虽然方便快 捷但是风险是必须要认真评估的);(2)错误回显(如果将服务器的错误信息直接显示在页面上,攻击者可以通过非法参数引发页面错误从而通过错误信息了解数据库结构,Web应用应当设置友好的错误页,一方面符合最小惊讶原则,一方面屏蔽掉可能给系统带来危险的错误回显信息);(3)盲注。防范 SQL 注入攻击也可以采用消毒的方式,通过正则表达式对请求参数进行验证,此外,参数绑定也是很好的手段,这样恶意的 SQL 会被当做 SQL 的参数而不是命令被执行,JDBC 中的 PreparedStatement 就是支持参数绑定的语句对象,从性能和安全性上都明显优于 Statement。

54、什么是CSRF攻击?【困难】

答: CSRF 攻击(Cross Site Request Forgery,跨站请求伪造)是攻击者通过跨站请求,以合法的用户身份进行非法操作(如转账或发帖等)。CSRF 的原理是利用浏览器的 Cookie 或服务器的 Session,盗取用户身份,其原理如下图所示。防范 CSRF 的主要手段是识别请求者的身份,主要有以下几种方式:

(1)在表单中添加令牌(token);

(2)验证码;

(3)检查请求头中的 Referer。

令牌和验证都具有一次消费性的特征,因此在原理上一致的,但是验证码是一种糟糕的用户体验,不是必要的情况下不要轻易使用验证码,目前很多网站的做法是如果在短时间内多次提交一个表单未获得成功后才要求提供验证码,这样会获得较好的用户体验。

四、redis

55、使用redis有哪些好处?【基础】

答:

  • 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)

  • 支持丰富数据类型,支持string,list,set,sorted set,hash

  • 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行

  • 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

56、Redis有哪些数据结构?【基础】

答:字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。

57、如果有大量的key需要设置同一时间过期,一般需要注意什么?【中等】

答:如果大量的key过期时间设置的过于集中,到过期的那个时间点,redis可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。

58、为什么Redis需要把所有数据放到内存中?【中等】

答:Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天,redis将会越来越受欢迎。 如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。

59、Redis提供了哪几种持久化方式?【中等】

答:

  1. RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储。
  2. AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾。Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。
  3. 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式。
  4. 你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
  5. 最重要的事情是了解RDB和AOF持久化方式的不同,让我们以RDB持久化方式开始。

60、如何选择合适的持久化方式?【中等】

答:一般来说, 如果想达到足以媲美PostgreSQL的数据安全性, 你应该同时使用两种持久化功能。如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失,那么你可以只使用RDB持久化。

有很多用户都只使用AOF持久化,但并不推荐这种方式:因为定时生成RDB快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比AOF恢复的速度要快,除此之外, 使用RDB还可以避免之前提到的AOF程序的bug。

61、redis支持的java客户端你用过哪个?【基础】

答: Jedis,Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持。

62、Redis集群的主从复制模型是怎样的?【困难】

答:为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品。

63、Redis集群之间是如何复制的?【中等】

答:异步复制。

64、怎么测试Redis的连通性?【基础】

ping。

五、消息队列

65、为什么要用消息队列?【中等】

解耦、异步、削峰

  • A系统调用B系统、C系统,传统的调用是直接调用,但是当B系统说我不需要你提供数据了,这时候A需要改代码,C系统说我不需要某个字段了,这时候A也要改代码,如果又多了一个D系统,A又要写代码。为了实现解耦,引入消息队列,A将产生的数据丢到消息队列中,哪个系统需要 哪个系统就去取;
  • A系统调用B系统,B系统由于某个需要调用第三方接口超时,导致A系统响应速度慢,而B系统的好坏又不会影响业务逻辑,所以可以改为A异步调用B,A将消息丢到消息队列中,B系统订阅消息,实现A的快速响应;
  • 当大量流量请求到系统A时,由于数据库的处理能力有限,造成数据库连接异常。使用消息队列,大量请求先丢到消息队列中,系统A使用按批拉数据的方式,批量处理数据,生产中,高峰期短暂的消息积压是允许的。

66、使用消息队列有什么缺点【中等】

  • 系统复杂性增加:加了消息队列,需要保证消息不会重复消费,需要保证消息的可靠性,需要保证消息队列的高可用
  • 系统的可用性降低:如果消息队列挂了,那么系统也会受到影响

67、为什么选用RocketMQ;RocketMQ和ActiveMQ的区别【困难】

RocketMQ模型简单、接口易用,在阿里大规模使用,社区活跃,单机吞吐量10万级,可用性非常高,消息理论上不会丢失;

  • ActiveMQ严格遵循JMS规范,可持久化到内存、文件、数据库,可用性高主要是主从,多语言支持,消失丢失率低;
  • RocketMQ持久化到磁盘文件,可用性非常高,支持分布式,只支持Java,消息理论上不会丢失;

68、RocketMQ是怎么保证系统高可用的?【困难】

  • 多Master部署,防止单点故障;
  • 主从结构,消息冗余,防止消息丢失;

69、消息中间件集群崩溃,如何保证百万生产数据不丢失?【中等】
答: 把消息持久化写入到磁盘上去 。

六、spring boot

70、Spring Boot 的核心配置文件有哪几个?它们的区别是什么?【中等】

Spring Boot 的核心配置文件是 application 和 bootstrap 配置文件。

application 配置文件这个容易理解,主要用于 Spring Boot 项目的自动化配置。

bootstrap 配置文件有以下几个应用场景:

  • 使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中添加连接到配置中心的配置属性来加载外部配置中心的配置信息;

  • 一些固定的不能被覆盖的属性;

  • 一些加密/解密的场景;

71、Spring Boot 的配置文件有哪几种格式?它们有什么区别?【中等】

.properties 和 .yml,它们的区别主要是书写格式不同。

1).properties

app.user.name = javastack

2).yml

app:
  user:
    name: javastack

另外,.yml 格式不支持 @PropertySource 注解导入配置。

72、Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?【基础】

启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:

  • @SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。

  • @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能:@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })。

  • @ComponentScan:Spring组件扫描。

73、开启 Spring Boot 特性有哪几种方式?【基础】

1)继承spring-boot-starter-parent项目

2)导入spring-boot-dependencies项目依赖

74、Spring Boot 需要独立的容器运行吗?【基础】

可以不需要,内置了 Tomcat/ Jetty 等容器。
75、如何在 Spring Boot 启动的时候运行一些特定的代码?【中等】

Spring Boot Runner启动器,可以实现接口 ApplicationRunner 或者 CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个 run 方法。

76、Spring Boot 有哪几种读取配置的方式?【中等】

Spring Boot 可以通过 @PropertySource,@Value,@Environment, @ConfigurationProperties 来绑定变量。

实例:

单个注入:@Value("${book.author}"),

映射一个类:@ConfigurationProperties(prefix="author",locations={"classpath:author.properties"})通过prefix指定前缀,通过locations指定位置
77、Spring Boot 如何定义多套不同环境配置?【中等】

提供多套配置文件,按照application-xxx.properties格式建立文件,并在application.properties中指定。如:

application.properties
 
application-dev.properties
 
application-test.properties
 
application-prod.properties

78、SpringBoot中的定时任务如何实现?【中等】

通过配置注解@EnableScheduline来开启对计划任务的支持,然后再要执行的任务上加注解@Scheduled。

79、我们如何连接一个像 MYSQL 或者 orcale 一样的外部数据库?【中等】

让我们以 MySQL 为例来思考这个问题:

第一步 - 把 mysql 连接器的依赖项添加至 pom.xml

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>

第二步 - 配置你的 MySQL 数据库连接

配置 application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/todo_example
spring.datasource.username=todouser
spring.datasource.password=YOUR_PASSWORD   

第三步 - 重新启动,你就准备好了!

七、spring cloud

80、什么是微服务【中等】

  • 以前的模式是 所有的代码在同一个工程中 部署在同一个服务器中 同一个项目的不同模块不同功能互相抢占资源

  • 微服务 将工程根据不同的业务规则拆分成微服务 微服务部署在不同的机器上 服务之间进行相互调用

  • Java微服务的框架有 dubbo(只能用来做微服务),spring cloud(提供了服务的发现,断路器等)

**81、微服务之间是如何独立通讯的spring Cloud和 Dubbo有哪些区別?【困难】 **

答:

  • springcloud服务注册中心是Spring Cloud Netflix Eureka

    dubbo的注册中心一般是zookeeper

  • dubbo只是类似Netflix的一个子集只有注册中心,其他springcloud组件没有

  • springcloud的调用方式是REST API

    dubbo的调用方式是RPC

    RPC服务提供方与调用方接口依赖方式太强

    我们为每个微服务定义了各自的service抽象接口

    并通过持续集成发布到私有仓库中

    调用方应用对微服务提供的抽象接口存在强依赖关系

    REST方式的服务依赖要比RPC方式的依赖更为灵活

  • Dubbo的文档可以说在国内开源框架中算是一流的,非常全,并且讲解的也非常深入,国内开发者来说,阅读起来更加容易上手

82、springcloud如何实现服务的注册和发现【中等】

  • 服务在发布时 指定对应的服务名(服务名包括了IP地址和端口) 将服务注册到注册中心(eureka或者zookeeper)

  • 这一过程是springcloud自动实现 只需要在main方法添加@EnableDisscoveryClient 同一个服务修改端口就可以启动多个实例

  • 调用方法:传递服务名称通过注册中心获取所有的可用实例 通过负载均衡策略调用(ribbon和feign)对应的服务

83、Ribbon和Feign的区别【中等】

Ribbon和Feign都是用于调用其他服务的,不过方式不同。

1.启动类使用的注解不同,Ribbon用的是@RibbonClient,Feign用的是@EnableFeignClients。

2.服务的指定位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。

3.调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。

Feign则是在Ribbon的基础上进行了一次改进,采用接口的方式,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建http请求。不过要注意的是抽象方法的注解、方法签名要和提供服务的方法完全一致。

84、springcloud断路器的作用【中等】

当一个服务调用另一个服务由于网络原因或者自身原因出现问题时 调用者就会等待被调用者的响应 当更多的服务请求到这些资源时。导致更多的请求等待 这样就会发生连锁效应(雪崩效应) 断路器就是解决这一问题

85、springcloud如何实现服务的注册和发现【中等】

答:服务在发布时 指定对应的服务名,服务名包括了IP地址和端口,将服务注册到注册中心eureka或者zookeeper,这一过程是springcloud自动实现,只需要在main方法添加 @ EnableDisscoveryClient,同一个服务修改端口就可以启动多个实例。

86、springcloud中的组件有那些?【中等】

答:独挑大梁,独自启动不需要依赖其它组件

1)Eureka,服务注册中心,特性有失效剔除、服务保护

2)Dashboard,Hystrix仪表盘,监控集群模式和单点模式,其中集群模式需要收集器Turbine配合

3)Zuul,API服务网关,功能有路由分发和过滤

4)Config,分布式配置中心,支持本地仓库、SVN、Git、Jar包内配置等模式

润物无声,融合在每个微服务中、依赖其它组件并为其提供服务

1)Ribbon,客户端负载均衡,特性有区域亲和,重试机制

2)Hystrix,客户端容错保护,特性有服务降级、服务熔断、请求缓存、请求合并、依赖隔离

3)Feign,声明式服务调用本质上就是Ribbon+Hystrix

4)Stream,消息驱动,有Sink、Source、Processor三种通道,特性有订阅发布、消费组、消息分区

5)Bus,消息总线,配合Config仓库修改的一种Stream实现,

6)Sleuth,分布式服务追踪,需要搞清楚TraceID和SpanID以及抽样,如何与ELK整合

八、其他

87、cookie和session的区别【基础】

1、Cookies是一种能够让网站服务器把少量数据储存到客户端的硬盘或内存,或是从客户端的硬盘读取数据的一种技术。Cookies是当你浏览某网站时,由Web服务器置于你硬盘上的一个非常小的文本文件,它可以记录你的用户ID、密码、浏览过的网页、停留的时间等信息。session: 当用户请求来自应用程序的 Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。cookie机制:采用的是在客户端保持状态的方案,而session机制采用的是在服务端保持状态的方案。同时我们看到由于服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助cookie机制来达到保存标识的目的。

2、Session是服务器用来跟踪用户的一种手段,每个Session都有一个唯一标识:session ID。当服务器创建了Session时,给客户端发送的响应报文包含了Set-cookie字段,其中有一个名为sid的键值对,这个键值Session ID。客户端收到后就把Cookie保存浏览器,并且之后发送的请求报表都包含SessionID。HTTP就是通过Session和Cookie这两个发送一起合作来实现跟踪用户状态,Session用于服务端,Cookie用于客户端

88、一次完整的http请求过程【中等】

域名解析 --> 发起TCP的3次握手 --> 建立TCP连接后发起http请求 --> 服务器响应http请求,浏览器得到html代码 --> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户。

89、讲一下长连接【困难】

一、基于http协议的长连接

在HTTP1.0和HTTP1.1协议中都有对长连接的支持。其中HTTP1.0需要在request中增加”Connection: keep-alive“ header才能够支持,而HTTP1.1默认支持.

http1.0请求与服务端的交互过程:

  1. 客户端发出带有包含一个header:”Connection: keep-alive“的请求

  2. 服务端接收到这个请求后,根据http1.0和”Connection: keep-alive“判断出这是一个长连接,就会在response的header中也增加”Connection: keep-alive“,同是不会关闭已建立的tcp连接.

  3. 客户端收到服务端的response后,发现其中包含”Connection: keep-alive“,就认为是一个长连接,不关闭这个连接。并用该连接再发送request.转到a)。

二、发心跳包。每隔几秒就发一个数据包过去

90、TCP如何保证可靠传输?【困难】

  1. 三次握手。

  2. 将数据截断为合理的长度。应用数据被分割成 TCP 认为最适合发送的数据块(按字节编号,合理分片)

  3. 超时重发。当 TCP 发出一个段后,它启动一个定时器,如果不能及时收到一个确认就重发

  4. 对于收到的请求,给出确认响应

  5. 校验出包有错,丢弃报文段,不给出响应

  6. 对失序数据进行重新排序,然后才交给应用层

  7. 对于重复数据 , 能够丢弃重复数据

  8. 流量控制。TCP 连接的每一方都有固定大小的缓冲空间。TCP 的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。

  9. 拥塞控制。当网络拥塞时,减少数据的发送。

91、URI和URL的区别【中等】

URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。Web上可用的每种资源如HTML文档、图像、视频片段、程序等都是一个来URI来定位的

URI一般由三部组成:

  1. 访问资源的命名机制

  2. 存放资源的主机名

  3. 资源自身的名称,由路径表示,着重强调于资源。

URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。URL是Internet上用来描述信息资源的字符串,主要用在各种WWW客户程序和服务器程序上,特别是著名的Mosaic。采用URL可以用一种统一的格式来描述各种信息资源,包括文件、服务器的地址和目录等。

URL一般由三部组成:

  1. 协议(或称为服务方式)

  2. 存有该资源的主机IP地址(有时也包括端口号)

  3. 主机资源的具体地址。如目录和文件名等

92、http和https的区别?【中等】

  1. https协议需要到CA申请证书,一般免费证书很少,需要交费。

  2. http是超文本传输协议,信息是明文传输;https 则是具有安全性的ssl加密传输协 议。

  3. http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

  4. http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

  5. http默认使用80端口,https默认使用443端口

93、docker常用命令【中等】

1.docker images // 查看镜像
2.docker run 镜像名称   // 生成一个正在运行的容器实例
3.docker stop 容器名称   // 停止容器
4.docker rm 容器名称  // 删除容器
5.docker start 容器名称  // 启动容器
6.docker restart 容器名称  //重启容器
7.docker rmi 镜像名称  // 删除镜像
8.docker exec -it 容器名称 /bin/bash  // 进入容器
9.docker ps  // 显示正在运行的所有容器
10.docker ps -a  // 显示所有容器(包括已经停止的)
11.docker pull 镜像名称:版本号  // 拉取镜像

94、什么是Docker镜像?【中等】

Docker镜像是Docker容器的源代码。换句话说,Docker镜像用于创建容器。使用build命令创建映像,并且在使用run启动时它们将生成容器。镜像存储在Docker注册表http://registry.hub.docker.com中,因为它们可能变得非常大,镜像被设计为由其他镜像层组成,允许在通过网络传输镜像时发送最少量的数据。

95、什么是Docker容器?【中等】

Docker容器包括应用程序及其所有依赖项,但与其他容器共享内核,作为主机操作系统上用户空间中的独立进程运行。Docker容器不依赖于任何特定的基础架构:它们可以在任何计算机,任何基础架构和任何云中运行。

96、什么是Docker Hub?【中等】

Docker hub是一个基于云的注册表服务,允许您链接到代码存储库,构建镜像并测试它们,存储手动推送的镜像以及指向Docker云的链接,以便您可以将镜像部署到主机。它为整个开发流程中的容器镜像发现,分发和变更管理,用户和团队协作以及工作流自动化提供了集中资源。

97、什么是 Git 复刻(fork)?复刻(fork)、分支(branch)和克隆(clone)之间有什么区别?【中等】

  • 复刻(fork)

是对存储仓库(repository)进行的远程的、服务器端的拷贝,从源头上就有所区别。复刻实际上不是 Git 的范畴。它更像是个政治/社会概念。

  • 克隆(clone)

不是复刻,克隆是个对某个远程仓库的本地拷贝。克隆时,实际上是拷贝整个源存储仓库,包括所有历史记录和分支。

  • 分支(branch)

是一种机制,用于处理单一存储仓库中的变更,并最终目的是用于与其他部分代码合并。

98、“git pull”和“git fetch”之间有什么区别?【中等】

简单来说,git pull 是 git fetch + git merge。 当你使用 pull,Git 会试着自动为你完成工作。它是上下文(工作环境)敏感的,所以 Git 会把所有拉取的提交合并到你当前处理的分支中。

pull 则是 自动合并提交而没有让你复查的过程。如果你没有细心管理你的分支,你可能会频繁遇到冲突。

当你 fetch,Git 会收集目标分支中的所有不存在的提交,并将这些提交存储到本地仓库中。但Git 不会把这些提交合并到当前分支中。这种处理逻辑在当你需要保持仓库更新,在更新文件时又希望处理可能中断的事情时,这将非常实用。而将提交合并到主分支中,则该使用 merge。

99、使用Ajax的优缺点分别是什么?【中等】

优点

  • 交互性更好。来自服务器的新内容可以动态更改,无需重新加载整个页面。
  • 减少与服务器的连接,因为脚本和样式只需要被请求一次。
  • 状态可以维护在一个页面上。JavaScript 变量和 DOM 状态将得到保持,因为主容器页面未被重新加载。
  • 基本上包括大部分 SPA 的优点。

缺点

  • 动态网页很难收藏。
  • 如果 JavaScript 已在浏览器中被禁用,则不起作用。
  • 有些网络爬虫不执行 JavaScript,也不会看到 JavaScript 加载的内容。
  • 基本上包括大部分 SPA 的缺点。

100、跨域问题,谁限制的跨域,怎么解决【困难】

  1. 浏览器的同源策略导致了跨域
  2. 用于隔离潜在恶意文件的重要安全机制
  3. jsonp ,允许 script 加载第三方资源
  4. nginx 反向代理(nginx 服务内部配置 Access-Control-Allow-Origin *)
  5. cors 前后端协作设置请求头部,Access-Control-Allow-Origin 等头部信息
  6. iframe 嵌套通讯,postmessage
posted @ 2020-01-09 09:00  Java旅途  阅读(4111)  评论(0编辑  收藏  举报