Fork me on GitHub

你的面试题

你的面试题

引言

找工作对于每个人来说对都都意味着你将接受企业对你的考验。在接受考验之前我们应该做好准备,才能提高自己的信心进而坦然的迎接每一次考验。不断的积累经验,不气馁、不抱怨、不放弃直到找到属于自己的岗位,并为之努力。

java中有哪些集合,主要方法有哪些

主要有LinkedList,ArrayList,Vector等。下面是详细:
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap
List 的具体实现包括 ArrayList 和 Vector,它们是可变大小的列表,比较适合构建、存储和操作任何类型对象的元素列表。 List 适用于按数值索引访问元素的情形。

Map 提供了一个更通用的元素存储方法。 Map 集合类用于存储元素对(称作“键”和“值”)其中每个键映射到一个值。

List、Set、Map是否继承自Collection接口

List、Set 是,Map 不是。Map是键值对映射容器,与List和Set有明显的区别,而Set存储的零散的元素且不允许有重复元素,List是线性结构的容器,适用于按数值索引访问元素的情形。

List、Map、Set接口,存取元素时各自特点

List 以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存key-value值,value可多值。
List的遍历: List接口有size()和get()方法,用这两个方法可以实现对List的遍历。size()方法得到List中的元素个数。get()方法取得某个位置上的元素

List 和 set

List:元素是有序的,元素可以重复,因为该集合体系有索引
Set:元素是无序的,元素不可以重复(存入和取出的顺序不一定一致)

List中常见的三个子类

  1. ArrayList :底层的数据使用的是数组结构。 特点:查询速度很快,但是增删稍慢。线程不同步,效率高 。可变长度数组,默认容量为10的空列表,如果超过了,则50%的增加
  2. LinkedList :底层的数据使用的是链表数据结构。 特点:增删数度很快,但是查询稍慢。
  3. Vector:底层使用的是数组结构。枚举是Vector特有的取出方式是同步的,效率较低,被ArrayList替代。最早出现的。默认容量为10的空列表,如果超过了,则100%的增加.

ArrayList 与 LinkedList 的区别

最明显的区别是 ArrrayList 底层的数据结构是数组,支持随机访问,而 LinkedList 的底层数据结构是链表,不支持随机访问。使用下标访问一个元素,ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)。
1.LinkedList内部存储的是Node,不仅要维护数据域,还要维护prev和next,如果LinkedList中的结点特别多,则LinkedList比ArrayList更占内存。
插入删除操作效率:
2.LinkedList在做插入和删除操作时,插入或删除头部或尾部时是高效的,操作越靠近中间位置的元素时,需要遍历查找,速度相对慢一些,如果在数据量较大时,每次插入或删除时遍历查找比较费时。所以LinkedList插入与删除,慢在遍历查找,快在只需要更改相关结点的引用地址。
ArrayList在做插入和删除操作时,插入或删除尾部时也一样是高效的,操作其他位置,则需要批量移动元素,所以ArrayList插入与删除,快在遍历查找,慢在需要批量移动元素。
3.循环遍历效率:
由于ArrayList实现了RandomAccess随机访问接口,所以使用for(int i = 0; i < size; i++)遍历会比使用Iterator迭代器来遍历快
而由于LinkedList未实现RandomAccess接口,所以推荐使用Iterator迭代器来遍历数据。
因此,如果我们需要频繁在列表的中部改变插入或删除元素时,建议使用LinkedList,否则,建议使用ArrayList,因为ArrayList遍历查找元素较快,并且只需存储元素的数据域,不需要额外记录其他数据的位置信息,可以节省内存空间。

Java 中的 LinkedList 是单向链表还是双向链表

是双向链表。

Vector和ArrayList的区别

首先看这两类都实现List接口,而List接口一共有三个实现类,分别是 ArrayList、Vector 和 LinkedList 。List 用于存放多个元素,能够维护元素的次序,并且允许元素的重复。3个具体实现类的相关区别如下:

1.ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要将已经有数组的数据复制到新的存储空间中。当从 ArrayList 的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
2.Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
3.LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。

HashMap与HashTable的区别

1、HashMap 是非线程安全的,HashTable 是线程安全的。

2、HashMap 的键和值都允许有 null 值存在,而 HashTable 则不行。

3、因为线程安全的问题,HashMap 效率比 HashTable 的要高。
HashMap 的实现机制:
维护一个每个元素是一个链表的数组,而且链表中的每个节点是一个 Entry[] 键值对的数据结构。
实现了 数组+链表 的特性,查找快,插入删除也快。
对于每个 key , 他对应的数组索引下标是 int i = hash(key.hashcode)&(len-1);
每个新加入的节点放在链表首,然后该新加入的节点指向原链表首

HashMap,ConcurrentHashMap与LinkedHashMap的区别

ConcurrentHashMap是使用了锁分段技术技术来保证线程安全的,锁分段技术:首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问
ConcurrentHashMap 是在每个段(segment)中线程安全的
LinkedHashMap维护一个双链表,可以将里面的数据按写入的顺序读出

ConcurrentHashMap应用场景
1:ConcurrentHashMap 的应用场景是高并发,但是并不能保证线程安全,而同步的 HashMap 和 HashMap 的是锁住整个容器,而加锁之后 ConcurrentHashMap 不需要锁住整个容器,只需要锁住对应的 Segment 就好了,所以可以保证高并发同步访问,提升了效率。
2:可以多线程写。
ConcurrentHashMap把HashMap分成若干个Segmenet
1.get时,不加锁,先定位到segment然后在找到头结点进行读取操作。而value是volatile变量,所以可以保证在竞争条件时保证读取最新的值,如果读到的value是null,则可能正在修改,那么久调用ReadValueUnderLock函数,加锁保证读到的数据是正确的。

2.Put时会加锁,一律添加到hash链的头部。

3.Remove时也会加锁,由于next是final类型不可改变,所以必须把删除的节点之前的节点都复制一遍。

4.ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对Hash表的不同Segment进行的修改。
ConcurrentHashMap的应用场景是高并发,但是并不能保证线程安全,而同步的HashMap和HashTable的是锁住整个容器,而加锁之后ConcurrentHashMap不需要锁住整个容器,只需要锁住对应的segment就好了,所以可以保证高并发同步访问,提升了效率。

HashSet 和 HashMap 区别

HashSet:

HashSet实现了Set接口,它不允许集合中出现重复元素。当我们提到HashSet时,第一件事就是在将对象存储在

HashSet之前,要确保重写hashCode()方法和equals()方法,这样才能比较对象的值是否相等,确保集合中没有储存相同的对象。如果不重写上述两个方法,那么将使用下面方法默认实现:

public boolean add(Object obj)方法用在Set添加元素时,如果元素值重复时返回 “false”,如果添加成功则返回”true”

HashMap:

HashMap实现了Map接口,Map接口对键值对进行映射。Map中不允许出现重复的键(Key)。Map接口有两个基本的实现TreeMap和HashMap。TreeMap保存了对象的排列次序,而HashMap不能。HashMap可以有空的键值对(Key(null)-Value(null))HashMap是非线程安全的(非Synchronize),要想实现线程安全,那么需要调用collections类的静态方法synchronizeMap()实现。

public Object put(Object Key,Object value)方法用来将元素添加到map中。

总结:

HashMap 实现了 Map 接口;存储键值对;调用put()向map中添加元素;HashMap使用键(Key)计算Hashcode;HashMap相对于HashSet较快,因为它是使用唯一的键获取对象。

HashSet 实现了 Set 接口;仅存储对象;调用add()方法向Set中添加元素;HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false;HashSet较HashMap来说比较慢。

重载和重写的区别

  • 重载:允许存在一个以上的同名函数,只要它们的参数个数或参数类型不同即可。
  • 重写:当子类继承父类,沿袭了父类的功能到子类中,子类虽具备该功能,但功能内容不一致,这是使用覆盖特性,保留父类的功能定义,并重写功能内容。

forward 和redirect的区别

forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。

redirect就是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,一般来说浏览器会用刚才请求的所有参数重新请求,所以session,request参数都可以获取。

int 和 Integer 有什么区别

Java 提供两种不同的类型:引用类型和原始类型(或内置类型)。Int 是 java 的原始数据类型,Integer 是 java为int提供的封装类。Java为每个原始类型提供了封装类。
原始类型封装类,booleanBoolean,charCharacter,byteByte,shortShort,intInteger,longLong,floatFloat,doubleDouble
引用类型和原始类型的行为完全不同,并且它们具有不同的语义。引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始类型实例变量的缺省值与它们的类型有关

error和exception有什么区别

Error和Exception都是java错误处理机制的一部分,都继承了Throwable类。

Exception表示的异常,异常可以通过程序来捕捉,或者优化程序来避免。

Error表示的是系统错误,不能通过程序来进行错误处理

throw 和 throws 的区别

throw 用于抛出 java.lang.Throwable 类的一个实例化对象,意思是说你可以通过关键字 throw 抛出一个 Error 或者 一个Exception,如:throw new IllegalArgumentException(“size must be multiple of 2″) ;而throws 的作用是作为方法声明和签名的一部分,方法被抛出相应的异常以便调用者能处理。Java 中,任何未处理的受检查异常强制在 throws 子句中声明。

简单回答:

Throw写在代码块内,throw后面跟的是一个具体的异常实例
Throws写在方法前面后面,throws后面跟的是异常类,异常类可以出现多个

常见Runtime异常

  • ArithmeticException:算术异常
  • InstantiationException:对象初始化异常
  • IllegalArgumentException:参数不匹配异常
  • ArrayIndexOutOfBoundsException:数组下标越界
  • NullPointerException:空指针异常
  • NumberFormatException:数字转换异常

java 属性的可见性有那些

属性的可见性有:公有的(public) 保护的(protected) 默认的(default)私有的(private)

属性的访问权限

权限 public protected defalut private
同一个类中 OK OK OK OK
同一个包中 OK OK OK
子类(不同包) OK OK
不同包中 OK

线程与进程的区别

进程是系统进行资源分配和调度的一个独立单位,线程是CPU调度和分派的基本单位

进程和线程的关系:

  1. 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
  2. 资源分配给进程,同一进程的所有线程共享该进程的所有资源。
  3. 线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
  4. 线程是指进程内的一个执行单元,也是进程内的可调度实体。

线程与进程的区别:

  1. 调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
  2. 并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。
  3. 拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。
  4. 系统开销:在创建或撤销进程的时候,由于系统都要为之分配和回收资源,导致系统的明显大于创建或撤销线程时的开销。但进程有独立的地址空间,进程崩溃后,在保护模式下不会对其他的进程产生影响,而线程只是一个进程中的不同的执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但是在进程切换时,耗费的资源较大,效率要差些。

创建线程的两种方式

  1. 继承Thread类。
    • 定义类继承Thread;
    • 复写父类中的方法;目的:将自定义代码存储在run方法中,让线程运行。
    • 调用线程的start方法,该方法有两个作用:启动线程,调用run方法
  2. 实现Runnable接口
    1. 定义类实现Runnable接口。
    2. 覆盖Runnable接口中的run方法。
    3. 通过Thread类建立线程对象。
    4. 将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
    5. 调用Thread类的start方法开启线程并调用Runnable接口子类的run方法。

创建线程的实现方式和继承方式有什么区别

  1. 实现方式相比继承方式的好处: 避免了单继承的局限性(单继承只能继承一个父类)。在定义线程时,建议使用实现方式。
  2. 存放代码的位置不一样:
    • 继承Thread:线程代码存放Thread子类的run方法中
    • 实现Runnable,线程代码存在接口的子类的run方法。

实现Runnable接口的好处

  1. 将线程的任务从线程的子类中分离出来,进行了单独的封装。 按照面向对象的思想将任务的封装成对象。
  2. 避免了java单继承的局限性。

Runnable接口和Callable接口的区别

这是一个优点深度的问题。

Runnable接口中的run()方法的返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。

这其实是很有用的一个特性,因为多线程相比单线程更难、更复杂的一个重要原因就是因为多线程充满着未知性,某条线程是否执行了?某条线程执行了多久?某条线程执行的时候我们期望的数据是否已经赋值完毕?无法得知,我们能做的只是等待这条多线程的任务执行完毕而已。而Callable+Future/FutureTask却可以获取多线程运行的结果,可以在等待时间太长没获取到需要的数据的情况下取消该线程的任务,真的是非常有用。

线程同步的方法

  1. wait():让线程等待。将线程存储到一个线程池中。
  2. notify():唤醒被等待的线程。通常都唤醒线程池中的第一个。让被唤醒的线程处于临时阻塞状态。
  3. notifyAll(): 唤醒所有的等待线程。将线程池中的所有线程都唤醒。

启动一个线程是用run()还是start()

启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。

Java的数据结构有那些

  • 线性表(ArrayList)
  • 链表(LinkedList)
  • 栈(Stack)
  • 队列(Queue)
  • 图(Map)
  • 树(Tree)

Java中有几种数据类型

  1. 整型:byte,short,int,long
  2. 浮点型:float,double
  3. 字符型:char
  4. 布尔型:boolean

Java中的包装类都是那些

  1. byte:Byte
  2. short:Short
  3. int:Integer
  4. long:Long
  5. float:Float
  6. double:Double
  7. char:Character
  8. boolean:Boolean

Java最顶级的父类是哪个

Object

Object 的常用方有哪些

clone()、equals()、hashCode()、notify()、notifyAll()、toString()、wait()、finalize()

数组实例化有几种方式

静态实例化:创建数组的时候已经指定数组中的元素,int[] a=new int[]{1,3,3}

动态实例化:实例化数组的时候,只指定了数组程度,数组中所有元素都是数组类型的默认值

实例化数组后,能不能改变数组长度呢

不能,数组一旦实例化,它的长度就是固定的

String是最基本的数据类型吗

java.lang.String类是final类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,我们应该用StringBuffer类。

是否可以继承String类

String 类是final类,不可以被继承。

补充:继承String本身就是一个错误的行为,对String类型最好的重用方式是关联关系(Has-A)和依赖关系(Use-A)而不是继承关系(Is-A)

String类的常用方法有那些

charAt:返回指定索引处的字符
indexOf():返回指定字符的索引
replace():字符串替换
trim():去除字符串两端空白
split():分割字符串,返回一个分割后的字符串数组
getBytes():返回字符串的byte类型数组
length():返回字符串长度
toLowerCase():将字符串转成小写字母
toUpperCase():将字符串转成大写字符
substring():截取字符串
format():格式化字符串
equals():字符串比较

==与equlas有什么区别

==可以判断基本数据类型值是否相等,也可以判断两个对象指向的内存地址是否相同,也就是说判断两个对象是否是同一个对象,Equlas通常用来做字符串比较。

final关键字的作用

  1. 可以修饰类、函数、变量;
  2. 被final修饰的类不可以被继承。为了避免被继承,被子类复写。final class Demo { }
  3. 被final修饰的方法不可以被复写。final void show () { }
  4. 被final 修饰的变量是一个常量,只能赋值一次。
  5. 内部类定义在类中的局部位置上时,只能访问该局部被final修饰的局部变量。

static关键字有哪些作用

static 修饰变量、修饰方法;静态块;静态内部类;静态导包;

abstract class和interface有什么区别

抽象类与接口的区别:
1.接口可以多重继承 ,抽象类不可以
2.接口定义方法,不给实现;而抽象类可以实现部分方法
3.接口中基本数据类型的数据成员,都默认为static和final,抽象类则不是
如果事先知道某种东西会成为基础类,那么第一个选择就是把它变成一个接口。
只有在必须使用方法定义或者成员变量的时候,才应考虑采用抽象类。

final,finally,finalize的区别

final—修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重写。
  finally—再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。
  finalize—方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。

HTTP请求方法get和post有什么区别

  1. Post传输数据时,不需要在URL中显示出来,而Get方法要在URL中显示。
  2. Post传输的数据量大,可以达到2M,而Get方法由于受到URL长度限制,只能传递大约1024字节.
  3. Post就是为了将数据传送到服务器段,Get就是为了从服务器段取得数据.而Get之所以也能传送数据,只是用来设计告诉服务器,你到底需要什么样的数据.Post的信息作为http请求的内容,而Get是在Http头部传输的。
  4. 其他 HTTP 请求方法
  • HEAD 与 GET 相同,但只返回 HTTP 报头,不返回文档主体。
  • PUT上传指定的 URI 表示。
    DELETE 删除指定资源。
  • OPTIONS 返回服务器支持的 HTTP 方法
  • CONNECT 把请求连接转换到透明的 TCP/IP 通道。
  1. cookie数据存放在客户的浏览器上,session数据放在服务器上。
  2. cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。
  3. session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。
  4. 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
  5. 所以个人建议: 将登陆信息等重要信息存放为SESSION 其他信息如果需要保留,可以放在COOKIE中

Mysql 的分页 SQL 语句

select * from tablename limit m,n(n是指从第m+1条开始,取n条)

Mysql 优化

1.如果明确知道只有一条结果返回,limit1能够提高效率

2.把计算放在业务层而不是数据库层,除了节省数据的 CPU ,还有意想不到的查询缓存优化效果。

3.强制类型转换会全表扫描

4.在属性上进行计算不能命中索引

5.使用 ENUM 而不是字符串

6.数据分区度不大的字段不宜使用索引

7.负向查询和前导模糊查询不能使用索引

8.用TRUNCATE替代DELETE

9.删除重复记录

10.用Where子句替换HAVING子句

11.用EXISTS替代IN、用NOT EXISTS替代NOT IN

12.用索引提高效率

13.用EXISTS替换DISTINCT

14.用>=替代>

15.用IN来替换OR

String s = new String(“xyz”);创建了几个字符串对象

两个对象,一个是静态区的”xyz”,一个是用new创建在堆上的对象。

用Java写一个单例类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
饿汉式单例:
public class Singleton {
private Singleton(){}
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
懒汉式单例(线程安全):
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static synchronized Singleton getInstance(){
if (instance == null) instance = new Singleton();
return instance;
}
}

用Java写一个冒泡排序

冒泡排序几乎是个程序员都写得出来,但是面试的时候如何写一个逼格高的冒泡排序却不是每个人都能做到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.Comparator;
/**
* 排序器接口(策略模式: 将算法封装到具有共同接口的独立的类中使得它们可以相互替换)
*
*/
public interface Sorter {
/**
* 排序
* @param list 待排序的数组
*/
public <T extends Comparable<T>> void sort(T[] list);
/**
* 排序
* @param list 待排序的数组
* @param comp 比较两个对象的比较器
*/
public <T> void sort(T[] list, Comparator<T> comp);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.util.Comparator;
/**
* 冒泡排序
*
*/
public class BubbleSorter implements Sorter {
@Override
public <T extends Comparable<T>> void sort(T[] list) {
boolean swapped = true;
for (int i = 1, len = list.length; i < len && swapped; ++i) {
swapped = false;
for (int j = 0; j < len - i; ++j) {
if (list[j].compareTo(list[j + 1]) > 0) {
T temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
swapped = true;
}
}
}
}
@Override
public <T> void sort(T[] list, Comparator<T> comp) {
boolean swapped = true;
for (int i = 1, len = list.length; i < len && swapped; ++i) {
swapped = false;
for (int j = 0; j < len - i; ++j) {
if (comp.compare(list[j], list[j + 1]) > 0) {
T temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
swapped = true;
}
}
}
}
}

Java解析XML的四种方法

  1. DOM4J生成和解析XML文档
  2. DOM生成和解析XML文档
  3. SAX生成和解析XML文档
  4. JDOM生成和解析XML

Maven有哪些优点

优点如下:
简化了项目依赖管理:
易于上手,对于新手可能一个”mvn clean package”命令就可能满足他的工作
便于与持续集成工具(jenkins)整合
便于项目升级,无论是项目本身升级还是项目使用的依赖升级。
有助于多模块项目的开发,一个模块开发好后,发布到仓库,依赖该模块时可以直接从仓库更新,而不用自己去编译。
maven有很多插件,便于功能扩展,比如生产站点,自动发布版本等

Spring有哪些优点

1.轻量级:Spring在大小和透明性方面绝对属于轻量级的,基础版本的Spring框架大约只有2MB。
2.控制反转(IOC):Spring使用控制反转技术实现了松耦合。依赖被注入到对象,而不是创建或寻找依赖对象。
3.面向切面编程(AOP): Spring支持面向切面编程,同时把应用的业务逻辑与系统的服务分离开来。
4.容器:Spring包含并管理应用程序对象的配置及生命周期。
5.MVC框架:Spring的web框架是一个设计优良的web MVC框架,很好的取代了一些web框架。
6.事务管理:Spring对下至本地业务上至全局业务(JAT)提供了统一的事务管理接口。
7.异常处理:Spring提供一个方便的API将特定技术的异常(由JDBC, Hibernate, 或JDO抛出)转化为一致的、Unchecked异常。

spring 主要使用了哪些 ,IOC和AOP实现原理是什么

spring主要功能有IOC,AOP,MVC等,IOC实现原理:先反射生成实例,然后调用时主动注入。AOP原理:主要使用java动态代理。

什么是IOC容器其优点

Spring IOC负责创建对象、管理对象(通过依赖注入)、整合对象、配置对象以及管理这些对象的生命周期。
优点:
IOC或依赖注入减少了应用程序的代码量。它使得应用程序的测试很简单,因为在单元测试中不再需要单例或JNDI查找机制。简单的实现以及较少的干扰机制使得松耦合得以实现。IOC容器支持勤性单例及延迟加载服务。

什么是 AOP

Spring 面向切面编程(AOP),利用AOP可以对业务逻辑的各个部分隔离,从而使的业务逻辑各部分的耦合性降低,提高程序的可重用性,踢开开发效率,主要功能:日志记录,性能统计,安全控制,事务处理,异常处理等。AOP实现原理是java动态代理,但是jdk的动态代理必须实现接口,所以 Spring 的 AOP 是用 cglib 这个库实现的,cglis 使用里 asm 这个直接操纵字节码的框架,所以可以做到不使用接口的情况下实现动态代理。

AOP与OOP的区别

OOP 面向对象编程,针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程的某个步骤或阶段,以获得逻辑过程的中各部分之间低耦合的隔离效果。这两种设计思想在目标上有着本质的差异。

举例:

对于“雇员”这样一个业务实体进行封装,自然是OOP的任务,我们可以建立一个“Employee”类,并将“雇员”相关的属性和行为封装其中。而用AOP 设计思想对“雇员”进行封装则无从谈起。

同样,对于“权限检查”这一动作片段进行划分,则是AOP的目标领域。

OOP面向名次领域,AOP面向动词领域。

总之AOP可以通过预编译方式和运行期动态代理实现在不修改源码的情况下,给程序动态同意添加功能的一项技术。

Spring 的依赖注入方式有哪一些

Spring 的依赖注入可以有两种方式来完成:setter 方法注入和构造方法注入。
构造器依赖注入:构造器依赖注入在容器触发构造器的时候完成,该构造器有一系列的参数,每个参数代表注入的对象。
Setter方法依赖注入:首先容器会触发一个无参构造函数或无参静态工厂方法实例化对象,之后容器调用bean中的setter方法完成Setter方法依赖注入。

SpringMVC运行原理

  1. 客户端请求提交到DispatcherServlet
  2. 由DispatcherServlet控制器查询HandlerMapping,找到并分发到指定的Controller中。
  3. Controller调用业务逻辑处理后,返回ModelAndView
  4. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
  5. 视图负责将结果显示到客户端

关于职业规划

关于我的职业规划,我把它分成三个阶段:

第一个阶段是三年,在这三年里,我要学会快速融入到公司的团队中,知道如何团结协作、如何使用项目管理工具、项目版本如何控制、自己写的代码如何测试如何在线上运行、如何去优化自己的代码。能够快速的理解项目相关的业务,对于复杂的业务能够考虑到可能会出现的多种情况以及解决方案。积累一定的开发经验。除了完成工作以外,在空余的时间里,研究各种技术实现细节, 对JDK 的源码和用到的框架进行深入的研究并且多做总结,写一些博客,在 Github 上分享技术。多看书,系统的学习。

第二个阶段是五年,也就是又过了两年,我在要具备在技术上独挡一面的能力并且清楚自己未来的方向,从一个写代码逐步走向系统分析师或是架构师,成为项目组中不可或缺的人物。

第三个阶段是十年,成为一名对行业有着深入认识、对技术有着深入认识、能从零开始对一个产品进行分析。

离职原因

个人发展原因。因为目前的工作太安逸,没有挑战,公司整体上都很稳定,也没有什么发展空间,我希望有一份比较有挑战的工作,毕竟我现在还年轻,是拼搏的年华,也需要成长。

坚持原创技术分享,您的支持将鼓励我继续创作!