2020春招面经汇总带答案

2020春招java开发面经汇总,面试了4家(阿里,中国移动,湖南长城金融,上海数慧)总结的java开发岗面经,不太全。

 

1.java 类装载过程
  答:装载--》链接(验证,准备,解析)--》初始化--》使用--》卸载

2.servlet是线程安全的吗

答:Servlet的生命周期分为4个阶段:加载、初始化(init)、服务(service)、销毁(destroy)。Servlet 默认是单例模式,在web 容器中只创建一个实例,所以多个线程同时访问servlet的时候,Servlet是线程不安全的。
服务阶段主要调用service()方法或者doGet()/doPost()方法。
doGet()方法:处理客户端发出的HTTP Get请求
doPost()方法:处理客户端发出的HTTP Post请求
例如:
@WebServlet("/Hello")
public class Hello extends HttpServlet {
    protected void doGet (HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
        response.getWriter().append("Served at: ").append(request.getContextPath());
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

3.了解spring aop吗?

答:剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

4.单例模式了解吗?
 答:
 饿汉模式://线程安全
     public class Singleton {
    
    private Singleton() {
 }       // 必须是私有构造方法


    
    private static Singleton instance = new Singleton();

    
    public static Singleton getInstance() {
        return instance;
    }

     }

  懒汉模式://线程不安全
    class Singleton {
    
        private Singleton() {
 }

  // 必须是私有构造方法


  
        private static Singleton instance = null;

    
        public static Singleton getInstance() {

                if (instance == null) {
            
                instance = new Singleton();
        
            }
        
                return instance;
    
        }
    
}

  双重检查锁://线程安全
    public class Singleton {
    
        private Singleton() {
 }

 // 必须是私有构造方法


   
        private static volatile Singleton instance = null;

    
        public static Singleton getInstance() {
        
            if (instance == null) {
            
                synchronized (Singleton.class) {
                
                    if (instance == null) {
                    
                        instance = new Singleton();
                
                    }
            
                }
        
            }
        
        return instance;
    
        }
    
}

5.集合有哪些,底层数据结构是什么。

答:Map、Set、List


6。String   StringBuffer   StringBuilder区别
   答: 1.运行速度快慢为:StringBuilder > StringBuffer > String
    2.String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的(故线程安全),但后两者的对象是变量,是可以更改的
    3.在线程安全上,StringBuilder是线程不安全的,而StringBuffer(用synchronized关键字同步)和String是线程安全的

7.springIOC的底层实现。

IOC【Inverse Of Control】控制反转:所谓控制反转就是把对象(bean)和维护对象(bean)之间的关系的权利转移到Spring容器中去了(ApplicationContext.xml)而程序本身不在维护了
DI【Dependency Injection】依赖注入:实际上DI和IOC是同一个概念,因为在ApplicationContext.xml配置文件中bean和bean之间通过ref来维护的时候是相互依赖的,所以又叫做依赖注入。也就是控制反转。

答:通过Dom4j+java反射
         1.解析xml
         2.使用beanid查找对应的xml节点   获取class 节点属性
         3.使用java的反射机制初始化类
         4.使用java的反射机制给私有属性赋值

详细步骤
1.利用传入的参数获取xml文件的流,并且利用dom4j解析成Document对象
2.对于Document对象获取根元素对象后对下面的标签进行遍历,判断是否有符合的id.
3.如果找到对应的id,相当于找到了一个Element元素,开始创建对象,先获取class属性,根据属性值利用反射建立对象.
4.遍历标签下的property标签,并对属性赋值.注意,需要单独处理int,float类型的属性.因为在xml配置中这些属性都是以字符串的形式来配置的,因此需要额外处理.
5.如果属性property标签有ref属性,说明某个属性的值是一个对象,那么根据id(ref属性的值)去获取ref对应的对象,再给属性赋值.
6.返回建立的对象,如果没有对应的id,或者下没有子标签都会返回null。


8.java多态
   答:多态是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作


9.TCP/UDP

答:(1)TCP面向连接;UDP面向无连接 
(2)TCP保证数据正确性;UDP可能丢包 
(3)TCP传输速度慢;UDP速度快 
(4)每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信 
(5)TCP对系统资源要求较多,UDP对系统资源要求较少。 


10.JVM

答:一共分为5个区:方法区、虚拟机栈、本地方法栈、堆、程序计数器。

方法区:
1. 有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生GC,在这里进行的GC主要是对方法区里的常量池和对类型的卸载
2. 方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。
3. 该区域是被线程共享的。
4. 方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中。

虚拟机栈:
1. 虚拟机栈也就是我们平常所称的栈内存,它为java方法服务,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。
2. 虚拟机栈是线程私有的,它的生命周期与线程相同。
3. 局部变量表里存储的是基本数据类型、returnAddress类型(指向一条字节码指令的地址)和对象引用,这个对象引用有可能是指向对象起始地址的一个指针,也有可能是代表对象的句柄或者与对象相关联的位置。局部变量所需的内存空间在编译期间确定
4.操作数栈的作用主要用来存储运算结果以及运算的操作数,它不同于局部变量表通过索引来访问,而是压栈和出栈的方式
5.每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接.动态链接就是将常量池中的符号引用在运行期转化为直接引用。

本地方法栈
本地方法栈和虚拟机栈类似,只不过本地方法栈为Native方法服务。


java堆是所有线程所共享的一块内存,在虚拟机启动时创建,几乎所有的对象实例都在这里创建,因此该区域经常发生垃圾回收操作。

程序计数器
内存空间小,字节码解释器工作时通过改变这个计数值可以选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。该内存区域是唯一一个java虚拟机规范没有规定任何OOM情况的区域。


11.线程安全

答:wait()和sleep()的区别

   sleep来自Thread类,和wait来自Object类
   调用sleep()方法的过程中,线程不会释放对象锁。而 调用 wait 方法线程会释放对象锁
   sleep睡眠后不出让系统资源,wait让出系统资源其他线程可以占用CPU
   sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒
 


12.hashmap 、hashtable、ConcurrentHashMap 原理、区别

HashTable
底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
初始size为11,扩容:newsize = olesize*2+1
计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length

HashMap
底层数组+链表实现,可以存储null键和null值,线程不安全
初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
计算index方法:index = hash & (tab.length – 1)
 

HashMap的初始值还要考虑加载因子:

 哈希冲突:若干Key的哈希值按数组大小取模后,如果落在同一个数组下标上,将组成一条Entry链,对Key的查找需要遍历Entry链上的每个元素执行equals()比较。
加载因子:为了降低哈希冲突的概率,默认当HashMap中的键值对达到数组大小的75%时,即会触发扩容。因此,如果预估容量是100,即需要设定100/0.75=134的数组大小。
空间换时间:如果希望加快Key查找的时间,还可以进一步降低加载因子,加大初始大小,以降低哈希冲突的概率。
HashMap和Hashtable都是用hash算法来决定其元素的存储,因此HashMap和Hashtable的hash表包含如下属性:

容量(capacity):hash表中桶的数量
初始化容量(initial capacity):创建hash表时桶的数量,HashMap允许在构造器中指定初始化容量
尺寸(size):当前hash表中记录的数量
负载因子(load factor):负载因子等于“size/capacity”。负载因子为0,表示空的hash表,0.5表示半满的散列表,依此类推。轻负载的散列表具有冲突少、适宜插入与查询的特点(但是使用Iterator迭代元素时比较慢)

ConcurrentHashMap
底层采用分段的数组+链表实现,线程安全
通过把整个Map分为N个Segment,可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。(读操作不加锁,由于HashEntry的value变量是 volatile的,也能保证读取到最新的值。)
Hashtable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占,ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术
有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁
扩容:段内扩容(段内元素超过该段对应Entry数组长度的75%触发扩容,不会对整个Map进行扩容),插入前检测需不需要扩容,有效避免无效扩容


区别:

1.继承的父类不同,HashMap继承的是AbstractMap类,而HashTable继承的是Dictionary 类;

2.初始容量和扩容量不同,HashMap初始容量为16个字节,扩容为原来的2倍,而 HashTable初始容量为11个字节,扩容增量为原来的2倍+1;

3.HashMap允许K/V存在null值,但是HashTable不允许K/V为null;

4.HashMap为线程不安全的,且不同步,在多线程并发过程中可能会产生死锁问题, 需要自己手动同步处理,而HashTable是线程安全的,在每个方法中都加了 synchronized同步锁,就相当于是加了同步锁的HashMap;

5.迭代器不同,两者都使用了Iterator,HashMap的Iterator是fail-fast迭代器,HashTable 还使用了Enumeration的方式,JDK8之前HashTable是没有fail-fas机制,在版本8之后 也是用的fail-fas;

6.HashMap比HashTable效率高,当需要多线程操作时可以使用CurrentHashMap, CurrentHashMap是线程安全的,而且效率远高于HashTable,因为CurrentHashMap 采用了分段锁,并不对整段数据进行锁定;

7.添加K-V时的取Hash值算法不同,HashMap添加元素时使用的时自定义哈希算法, 而HashTable没用自定义哈希算法,直接采用的是Key的HashCode()方法;

13.valotile关键字如何使用?

答:一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

  1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。

  2)禁止进行指令重排序。


14.springMVC实现过程?

答:1、用户发送请求到前端控制器(DispatcherServlet)。

2、前端控制器请求处理器映射器(HandlerMapping)去查找处理器(Handler)。

3、找到以后处理器映射器(HandlerMappering)向前端控制器返回执行链(HandlerExecutionChain)。

4、前端控制器(DispatcherServlet)调用处理器适配器(HandlerAdapter)去执行处理器(Handler)。

5、处理器适配器去执行Handler。

6、处理器执行完给处理器适配器返回ModelAndView。

7、处理器适配器向前端控制器返回ModelAndView。

8、前端控制器请求视图解析器(ViewResolver)去进行视图解析。

9、视图解析器向前端控制器返回View。

10、前端控制器对视图进行渲染。

11、前端控制器向用户响应结果。


15 数据库
事务 ACID 
隔离特性与级别高低,以及Mysql、Orcle默认是哪个
数据库脏读、幻读是什么?隔离特性有什么影响?
索引的类型(我回答b树,b+树)并介绍他们的原理和特点

答:(1)原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

(2)一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
  如:拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

(3)隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
  即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

(4)持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
  例如:我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

数据库幻读、脏读、不可重复读是什么?

答:
  幻读:幻读的重点在于新增或者删除,同样条件下两次读出来的记录数不一样。


脏读定义:
1)说法1:指在一个事务处理过程里读取了另一个未提交的事务中的数据,读取数据不一致。
  2)说法2:指事务A对数据进行增删改操作,但未提交,另一事务B可以读取到未提交的数据。如果事务A这时候回滚了,则第二个事务B读取的即为脏数据。

不可重复读定义:
1)说法1:是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
  2)说法2:一个事务A中发生了两次读操作,第一次读操作和第二次读操作之间,另一个事务B对数据进行了修改,这时两个事务读取的数据不一致。

不可重复读和脏读的区别:
脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。

隔离特性与级别高低,以及Mysql、Orcle默认是哪个?

答:  ① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
      ② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
      ③ Read committed (读已提交):可避免脏读的发生。
      ④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)。
  在MySQL数据库中,支持上面四种隔离级别,默认的为Repeatable read (可重复读);而在Oracle数据库中,只支持Serializable (串行化)级别和Read committed (读已提交)这两种级别,其中默认的为Read committed级别。


索引的类型并介绍他们的原理和特点?

索引是对数据库表中一个或多个列的值进行排序的数据结构,以协助快速查询、更新数据库表中数据。

答:1.普通索引 :这是最基本的索引,它没有任何限制
2.唯一索引:与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值(注意和主键不同)。
3.主键索引(primary key) :它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引:  
4.组合索引:将多个字段放到一个索引里,例如:ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age);

Mysql的两种引擎,即MyISAM(不支持事务处理)和InnoDB(支持ACID兼容的事务处理)的索引都是使用b树的变种b+树存储的。
MyISAM是使用的非聚簇索引,索引树和数据存储分开,索引树只存储索引key值和数据的地址,而且所有的索引都是存储的这个地址;
InnoDB的索引大体上和MyISAM一样,不一样就在于它的数据存储方式不同,它采用主键的聚簇索引,将数据存在主键索引树上,辅键索引则是存储的主键key


16.spring aop

答:AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
可以用于:日志记录,性能统计,安全控制,事务处理,异常处理等等
Spring使用AOP的功能完成各种共用的模板功能,使得我们的业务代码与其它代码分开


17.java GC垃圾回收
  答:Java虚拟机中进行垃圾回收的场所有两个,一个是堆,一个是方法区。在堆中存储了Java程序运行时的所有对象信息,而垃圾回收其实就是对那些“死亡的”对象进行其所侵占的内存的释放,让后续对象再能分配到内存。

      大多数情况下,对象在新生代Eden区和一块survivor区中分配,当Eden区和survivor区没有足够空间进行分配时,虚拟机将发起一次Minor GC,将存活对象放到另一块surviver区,当survivor区大小不够时,把存活对象复制到老年代。当老年代中没有足够的内存空间来存放对象时,虚拟机会发起一次Major GC/Full GC。
    垃圾回收机制:
        1.引用计数算法(Reference Counting)
            给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的,这就是引用计数算法的核心
        2.可达性分析算法(Reachability Analysis)


                  这是Java虚拟机采用的判定对象是否存活的算法。通过一系列的称为“GC Roots"的对象作为起始点,从这些结点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。可作为GC Roots的对象包括:虚拟机栈中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象。本地方法栈JNI引用的对象。
    
    垃圾收集算法:

(1)、标记-清楚算法(Mark-Sweep)


                        用在老生代中, 先对对象进行标记,然后清除。标记过程就是第五部分提到的标记过程。值得注意的是,使用该算法清楚过后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

.      
              (2)、复制算法(Copying)

                 
                    用在新生代中,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另外一块上,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可。


18..集合有哪些,底层数据结构是什么。

答:
1.List :有序,可以重复的集合

List 接口的三个典型实现:

  ①、List list1 = new ArrayList();

    底层数据结构是动态数组,查询快,增删慢;线程不安全,效率高

   ②、List list2 = new Vector();

    底层数据结构是数组,查询快,增删慢;线程安全,效率低,几乎已经淘汰了这个集合

   ③、List list3 = new LinkedList();

    底层数据结构是双向循环链表,查询慢,增删快;线程不安全,效率高


2.Set:典型实现 HashSet()是一个无序,不可重复的集合
    Set hashSet = new HashSet();
  ①、HashSet:不能保证元素的顺序;不可重复;不是线程安全的;集合元素可以为 NULL;
  ②、其底层其实是一个数组,存在的意义是加快查询速度。我们知道在一般的数组中,元素在数组中的索引位置是随机的,元素的取值和元素的位置之间不存在确定的关系,因此,在数组中查找特定的值时,需要把查找值和一系列的元素进行比较,此时的查询效率依赖于查找过程中比较的次数。而 HashSet 集合底层数组的索引和值有一个确定的关系:index=hash(value),那么只需要调用这个公式,就能快速的找到元素或者索引。
  ③、对于 HashSet: 如果两个对象通过 equals() 方法返回 true,这两个对象的 hashCode 值也应该相同。

3.Map:key-value 的键值对,key 不允许重复,value 可以。
主要有:hashmap、hashtable、concurrenthashmap,详解见上面。

 

19.hashmap Arraylist 原理

答:相同点:

    1.都是线程不安全,不同步


            2.都可以储存null值

    
            3.获取元素个数方法一样,都用size()方法获取

    

区别:

      1.实现的接口

    ArrayList实现了List接口(Collection(接口)->List(接口)->ArrayList(类)),底层使用的是数组;而HashMap现了Map接口(Map(接口)->HashMap(类)),底                                       层使用的是Hash算法存储数据。

    
            2.存储元素

      ArrayList以数组的方式存储数据,里面的元素是有顺序,可以重复的;而HashMap将数据以键值对的方式存储,键的哈希码(hashCode)不可以相同,相同后面的值会将前                       面的值覆盖,值可以重复,里面的元素无序。

    
            3.添加元素的方法

    ArrayList用add(Object object)方法添加元素,而HashMap用put(Object key, Object value)添加元素。

    
            4.默认的大小和扩容

    在 Java 7 中,ArrayList的默认大小是 10 个元素,HashMap 的默认大小是16个元素(必须是2的幂)。
            5. ArrayList扩容增量:原容量的0.5倍+1,如 ArrayList的容量为10,一次扩容后是容量为16; HashMap扩容增量:原容量的 1 倍
               hashmap扩容增量:原容量的2倍,HashMap的容量为16,一次扩容后是容量为32

    使用场景:

        如果需要快速随机访问元素,应该使用ArrayList。需要键值对形式的数据时,应该使用HashMap


 

20.快速排序的思路以及在最好的情况下和最坏情况下的时间复杂度

 答:快速排序的原理:选择一个关键值作为基准值。比基准值小的都在左边序列(一般是无序的),比基准值大的都在右边(一般是无序的)。一般选择序列的第一个元素。接着分别比较左右两边的序列,重复上述      的循环。

    时间复杂度:最优的情况下空间复杂度为:O(logn)  ;每一次都平分数组的情况
            最差的情况下空间复杂度为:O( n^2 )   ;退化为冒泡排序的情况
            一般情况:时间复杂度为O(nlogn)


21.B树和B+树的区别
 答:B和B+树的区别在于,B+树的非叶子结点只包含索引信息,不包含实际的值,所有的叶子结点和相连的节点使用链表相连,便于区间查找和遍历。

    B+ 树的优点在于:
            由于B+树在内部节点上不包含数据信息,因此在内存页中能够存放更多的key。 数据存放的更加紧密,具有更好的空间局部性。因此访问叶子节点上关联的数据也具有更好的缓存命中率。
            B+树的叶子结点都是相链的,因此对整棵树的遍历只需要一次线性遍历叶子结点即可。而且由于数据顺序排列并且相连,所以便于区间查找和搜索。而B树则需要进行每一层的递归遍历。相邻的           元素可能在内存中不相邻,所以缓存命中性没有B+树好。

    B树优点,其优点在于,由于B树的每一个节点都包含key和value,因此经常访问的元素可能离根节点更近,因此访问也更迅速。

 

22.HashMap是如何解决哈希冲突的
    答:1.开放地址法
    2.链地址法

 

23.Mysql 如何优化查询操作
    答:1.用索引
    2.优化sql语句

24.哪些设计模式
  答:设计模式主要分三个类型:创建型、结构型和行为型。共23种
 
其中创建型有
    一、Singleton,单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点 
    二、Abstract Factory,抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。 
    三、Factory Method,工厂方法:定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类。 
    四、Builder,建造模式:将一个复杂对象的构建与他的表示相分离,使得同样的构建过程可以创建不同的表示。 
    五、Prototype,原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型来创建新的对象。 
行为型有: 
    六、Iterator,迭代器模式:提供一个方法顺序访问一个聚合对象的各个元素,而又不需要暴露该对象的内部表示。 
    七、Observer,观察者模式:定义对象间一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知自动更新。 
    八、Template Method,模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,TemplateMethod使得子类可以不改变一个算法的结构即可以重定义该算法得某些特定步骤。 
    九、Command,命令模式:将一个请求封装为一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录请求日志,以及支持可撤销的操作。 
    十、State,状态模式:允许对象在其内部状态改变时改变他的行为。对象看起来似乎改变了他的类。 
    十一、Strategy,策略模式:定义一系列的算法,把他们一个个封装起来,并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。 
    十二、China of Responsibility,职责链模式:使多个对象都有机会处理请求,从而避免请求的送发者和接收者之间的耦合关系 
    十三、Mediator,中介者模式:用一个中介对象封装一些列的对象交互。 
    十四、Visitor,访问者模式:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这个元素的新操作。 
    十五、Interpreter,解释器模式:给定一个语言,定义他的文法的一个表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 
    十六、Memento,备忘录模式:在不破坏对象的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。 
结构型有: 
    十七、Composite,组合模式:将对象组合成树形结构以表示部分整体的关系,Composite使得用户对单个对象和组合对象的使用具有一致性。 
    十八、Facade,外观模式:为子系统中的一组接口提供一致的界面,fa?ade提供了一高层接口,这个接口使得子系统更容易使用。 
    十九、Proxy,代理模式:为其他对象提供一种代理以控制对这个对象的访问 
    二十、Adapter,适配器模式:将一类的接口转换成客户希望的另外一个接口,Adapter模式使得原本由于接口不兼容而不能一起工作那些类可以一起工作。 
    二十一、Decrator,装饰模式:动态地给一个对象增加一些额外的职责,就增加的功能来说,Decorator模式相比生成子类更加灵活。 
    二十二、Bridge,桥模式:将抽象部分与它的实现部分相分离,使他们可以独立的变化。 
    二十三、Flyweight,享元模式


25.乐观锁/悲观锁

   答:一、乐观锁
 总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制                   或CAS操作实现。

 
           version方式:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version                   值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。

    二.悲观锁
           总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等),当其他线程想要访问数据时,都需要阻塞挂起。可以依靠数据库实现,如行锁、读锁和写锁          等,都是在操作之前加锁,在Java中,synchronized的思想也是悲观锁。


数据库知识

 1.主键 超键 候选键 外键区别:
主    键:数据库表中对储存数据对象予以唯一和完整标识的数据列或属性的组合。一个数据列只能有一个主键,且主键的取值不能缺失,即不能为空值(Null)。

超    键:在关系中能唯一标识元组的属性集称为关系模式的超键。一个属性可以为作为一个超键,多个属性组合在一起也可以作为一个超键。超键包含候选键和主键。

候选键:是最小超键,即没有冗余元素的超键。

外    键:在一个表中存在的另一个表的主键称此表的外键。

2.什么是视图?以及视图的使用场景有哪些?
    视图是一种虚拟的表,具有和物理表相同的功能。可以对视图进行增,改,查,操作,试图通常是有一个表或者多个表的行或列的子集。对视图的修改不影响基本表。它使得我们获取数据更容易,相比多表查询。

    如下两种场景一般会使用到视图:

      不希望访问者获取整个表的信息,只暴露部分字段给访问者,所以就建一个虚表,就是视图。
      查询的数据来源于不同的表,而查询者希望以统一的方式查询,这样也可以建立一个视图,把多个表查询结果联合起来,查询者只需要直接从视图中获取数据,不必考虑数据来源于不同表所带来的差异。
    注意:这个视图是在数据库中创建的 而不是用代码创建的。

3.drop,delete与truncate的区别

   drop直接删掉表;truncate删除表中数据,再插入时自增长id又从1开始;delete删除表中数据,可以加where字句。
   DELETE语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作。TRUNCATE TABLE 则一次性地从表中删除所有的数据并不把单独的删除操作记录记入日志保存,删除行是不能恢复的。   并且在删除的过程中不会激活与表有关的删除触发器。执行速度快。

4.SQL 约束有哪几种?
     NOT NULL: 用于控制字段的内容一定不能为空(NULL)。
     UNIQUE: 控件字段内容不能重复,一个表允许有多个 Unique 约束。
     PRIMARY KEY: 也是用于控件字段内容不能重复,但它在一个表只允许出现一个。
     FOREIGN KEY: 用于预防破坏表之间连接的动作,也能防止非法数据插入外键列,因为它必须是它指向的那个表中的值之一
     CHECK: 用于控制字段的值范围。

5.外连接(左外连接、右外连接)和内连接的区别

   答:一、外连接
1.概念:包括左向外联接、右向外联接或完整外部联接

2.左连接:left join 或 left outer join
   (1)左向外联接的结果集包括 LEFT OUTER 子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值(null)。
   (2)sql 语句
   select * from table1 left join table2 on table1.id=table2.id
   -------------结果-------------
   idnameidscore
   ------------------------------
   1lee190
   2zhang2100
   4wangNULLNULL
   ------------------------------
   注释:包含table1的所有子句,根据指定条件返回table2相应的字段,不符合的以null显示

3.右连接:right join 或 right outer join
   (1)右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。
   (2)sql 语句
   select * from table1 right join table2 on table1.id=table2.id
   -------------结果-------------
   idnameidscore
   ------------------------------
   1lee190
   2zhang2100
   NULLNULL370


二、内连接
1.概念:内联接是用比较运算符比较要联接列的值的联接

2.内连接:join 或 inner join

3.sql 语句
select * from table1 join table2 on table1.id=table2.id
-------------结果-------------
idnameidscore
------------------------------
1lee190
2zhang2100
------------------------------
注释:只返回符合条件的table1和table2的列

Statement、PreparedStatement和CallableStatement区别

数据库函数和写入过程
model和实例的区别
左外连接两个表行数不一

 

计算机网络(讲一下三次握手和四次挥手的具体过程)

1.三次握手  四次挥手
 
三次握手:

最初两端的TCP进程都处于CLOSED关闭状态,客户端A主动打开连接,而服务器端B被动打开连接。(A、B关闭状态CLOSED——B收听状态LISTEN——A同步已发送状态SYN-SENT——B同步收到状态SYN-RCVD——A、B连接已建立状态ESTABLISHED)

B的TCP服务器进程先创建传输控制块TCB,准备接受客户进程的连接请求。然后服务器进程就处于LISTEN(收听)状态,等待客户的连接请求。若有,则作出响应。
1)第一次握手:A的TCP客户进程也是首先创建传输控制块TCB,然后向B发出连接请求报文段,(首部的同步位SYN=1,初始序号seq=x),(SYN=1的报文段不能携带数据)但要消耗掉一个序号,此时TCP客户进程进入SYN-SENT(同步已发送)状态。

2)第二次握手:B收到连接请求报文段后,如同意建立连接,则向A发送确认,在确认报文段中(SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y),测试TCP服务器进程进入SYN-RCVD(同步收到)状态;

3)第三次握手:TCP客户进程收到B的确认后,要向B给出确认报文段(ACK=1,确认号ack=y+1,序号seq=x+1)(初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。TCP连接已经建立,A进入ESTABLISHED(已建立连接)。
当B收到A的确认后,也进入ESTABLISHED状态。


为什么TCP客户端最后还要发送一次确认呢(为什么不是两次握手)?
一句话,主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误。


如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。

如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接受到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接。


四次挥手:

第一次挥手:(1) 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

第二次挥手:(2) 服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

第三次挥手:(3) 客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
            (4) 服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
第四次挥手:(5) 客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

为什么连接的时候是三次握手,关闭的时候却是四次握手?

答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

为什么A在TIME-WAIT状态必须等待2MSL的时间?

答:1)保证A发送的最后一个ACK报文段能够到达B。2)防止“已失效的连接请求报文段”出现在本连接中。(下面是详细解释)

1)这个ACK报文段有可能丢失,使得处于LAST-ACK状态的B收不到对已发送的FIN+ACK报文段的确认,B超时重传FIN+ACK报文段,而A能在2MSL时间内收到这个重传的FIN+ACK报文段,接着A重传一次确认,重新启动2MSL计时器,最后A和B都进入到CLOSED状态,若A在TIME-WAIT状态不等待一段时间,而是发送完ACK报文段后立即释放连接,则无法收到B重传的FIN+ACK报文段,所以不会再发送一次确认报文段,则B无法正常进入到CLOSED状态。

2)A在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。

MSL指的是任何IP数据报能够在因特网上存活的最长时间。假设现在一个MSL的时候,接收端需要发送一个应答,这时候,我们也必须等待这个应答的消失,这个应答的消失也是需要一个MSL,所以我们需要等待2MSL。
 

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值