Java后端面试题归纳

2017-10-26  本文已影响103人  谢随安

Java基础

Override、Overload和多态

多态和方法覆盖都设计到继承,继承是指派生类包含了基类的所有方法和属性,并能通过该派生类进行访问。继承类通过重用父类的方法并添加一些新的功能来扩展应用程序的功能。但是这会导致紧耦合,当要对父类进行修改时必须确认其所有子类的具体细节以防止阻断

抽象类和接口

抽象类呈现的是子类的通用特性,它定义了一些默认的行为,将具体的功能交给子类来实现。不能被实例化,只能被用作子类的超类,抽象类中可以包括抽象方法和具体方法

接口是抽象类的延伸(进一步抽象)。它是抽象方法的集合,接口中不能定义实现的方法。实现接口的非抽象类必须实现该接口的所有方法。

Java为了保证数据安全不允许多重继承,即继承只能指定一个父类,但是接口不同,一个类可以实现多个接口,不管这些接口之间有没有关系,因此多重继承可以由接口实现。

组合(合成)

代码的重用性可以通过继承和合成来实现,但是用合成实现代码重用比继承具有更好的封装性,因为对后端的修改无需任何对修改前端类的代码。

合成是实现类之间“has a”关系的设计技术。例如一个椅子有一个座位、一个靠背、几条腿。词组“has a”表示一把椅子所包含或使用的其他实体。

如果类之间不存在“is a”关系,建议采用合成来实现代码重用。

序列化和反序列化

在程序运行的过程中,所有的变量都是在内存中,变量可以被随时的修改,但是一旦程序结束,变量所占用的内存就被操作系统全部回收。如果没有把修改后的内容存储到磁盘上,下次重新运行程序,变量又会被初始化为最初值。
我们把变量从内存中变成可存储或传输的过程称之为序列化,序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化。

Java线程的实现方式有几种?

Java实现多线程的方式主要有两种,一种是继承Thread类,另一种是实现Runnable接口。

Thread类实现了Runnable接口,使用继承Thread类的方式实现线程的局限在于不支持多继承。两种实现方式创建的线程在工作时的性质一样,没有本质区别。

线程安全

线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

Java IO与NIO的区别

Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。它不能前后移动流中的数据。如果要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。增加了处理过程中的灵活性。但是,还要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不会覆盖缓冲区里尚未处理的数据。

阻塞与非阻塞IO

Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情。Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞。所以直至数据可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道。

选择器

Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

Java 的Map 与HashMap 还有 HashTable

Map是Java为数据结构中的“键值对”映射定义的一个抽象接口java.util.Map,此接口主要有四个常用的实现类,分别是HashMap、Hashtable、LinkedHashMap和TreeMap。

HasMap是基于“拉链法”实现的散列表。它根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap最多只允许一条记录的键为null,允许多条记录的值为null。HashMap非线程安全,即任一时刻可以有多个线程同时写HashMap,可能会导致数据的不一致,一般用于单线程程序中。如果需要满足线程安全,可以用 Collections的synchronizedMap方法使HashMap具有线程安全的能力,或者使用ConcurrentHashMap。

Hashtable是遗留类,很多映射的常用功能与HashMap类似,不同的是它继承自Dictionary类,并且是线程安全的,任一时间只有一个线程能写Hashtable,并发性不如ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。Hashtable不建议在新代码中使用,不需要线程安全的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换。

单例模式

数据库部分

事务的特性有哪些

四大特性(ACID):

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

一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

不考虑事务的隔离性会发生什么问题
  1. 脏读

脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据,即读取的不是自己想要的数据。

  1. 不可重复读

一个事务要读取的数据被另一个提交的事务篡改了。导致一个事务范围内多次查询却返回了不同的数据值。

  1. 虚读(幻读)

幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

事务的隔离级别有哪些
  1. Serializable (串行化):可避免脏读、不可重复读、幻读的发生。

  2. Repeatable read (可重复读):可避免脏读、不可重复读的发生。

  3. Read committed (读已提交):可避免脏读的发生。

  4. Read uncommitted (读未提交):最低级别,任何情况都无法保证。

四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别;隔离级别越高,执行效率就越低。

SQL分页查询是怎么实现的

大多数据库本身就有提供分页查询的功能,只是它们的分页查询的关键字与使用方式不同,比如SQL Server支持的是TOP,而MySQL用的则是LIMIT
TOP关键字在SQL语言中用来限制返回结果集中的记录条数,它有两个缺陷——不是标准SQL,且不支持跳过功能。SQL Server2012引入了对OFFSET-FETCH筛选的支持。OFFSET-FETCH支持跳过功能,这对针对特定页面的查询非常有用。:

  1. 返回确定数目的记录个数

语法格式: SELECT TOP n <列名表> FROM <表名> [查询条件]

其中,n为要返回结果集中的记录条数

  1. 返回结果集中指定百分比的记录数

语法格式: SELECT TOP n PERCENT <列名表> FROM <表名> [查询条件]

其中,n为所返回的记录数所占结果集中记录数目的百分比数

TOP选项是一个非常实用的筛选类型,但它有两个缺陷——不是标准SQL,且不支持跳过功能。标准SQL定义的TOP类似筛选称为OFFSET-FETCH,支持跳过功能,这对针对特定页面的查询非常有用。

数据库索引 Index

索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。与在表中搜索所有的行相比,数据库索引可以提高数据库表的数据访问速度。

数据库索引的特点:

a)避免进行数据库全表的扫描,大多数情况,只需要扫描较少的索引页和数据页,而不是查询所有数据页。而且对于非聚集索引,有时不需要访问数据页即可得到数据。

b)聚集索引可以避免数据插入操作,集中于表的最后一个数据页面。

c)在某些情况下,索引可以避免排序操作。

索引一般放在什么字段上?

一般索引会建立在主键和外键和where条件中常用的字段上。即为用来搜索、分类或分组的数据列设置索引。

尽量选择短小的值进行索引,这可以提高索引的性能。

数据库 Join

SQL join 用于根据两个或多个表中的列之间的关系,从这些表中查询数据。

Join有以下四种类型:

INNER JOIN

INNER JOIN 与 JOIN 是相同的。INNER JOIN 关键字在表中存在至少一个匹配时返回行。如果没有匹配,则不会列出这些列。

LEFT JOIN

LEFT JOIN 关键字会从左表那里返回所有的行,即使在右表中没有匹配的行。

RIGHT JOIN

RIGHT JOIN 关键字会从右表 (Orders) 那里返回所有的行,即使在左表 (Persons) 中没有匹配的行。

FULL JOIN

FULL JOIN 关键字会从左表 (Persons) 和右表 (Orders) 那里返回所有的行。如果 "Persons" 中的行在表 "Orders" 中没有匹配,或者如果 "Orders" 中的行在表 "Persons" 中没有匹配,这些行同样会列出。

数据库优化(不完整)
查询优化
  1. 设置索引

为一个没有索引的数据表加上索引通常可以使性能得到巨大的改进。

索引加快了查询数据速度,但会降低写数据表的速度。其次索引会占据磁盘空间。因此如果不需要某个索引来加快查询速度,就不要创建该索引。

  1. 选取数据类型

多用数值操作,少用字符串操作。

尽量使用能满足需求的小类型。

选用适用于存储引擎的存储格式。

NOT NULL数据列查询更快

  1. 批量加载,批量加载效率比单数据行加载高

  2. 更改用于调度和锁定的语句的调度优先权。改变语句的执行优先级,使用延迟插入、使用并发插入。

上一篇 下一篇

猜你喜欢

热点阅读