148道Java开发真实面试题及答案

1. Java的垮平台原理

JVM也是一个软件,不同的平台有不同的版本。我们编写的Java源码,编译后会生成一种 .class 文件,称为字节码文件。Java虚拟机就是负责将字节码文件翻译成特定平台下的机器码然后运行。也就是说,只要在不同平台上安装对应的JVM,就可以运行字节码文件,运行我们编写的Java程序。

而这个过程中,我们编写的Java程序没有做任何改变,仅仅是通过JVM这一”中间层“,就能在不同平台上运行,真正实现了”一次编译,到处运行“的目的。

JVM是一个”桥梁“,是一个”中间件“,是实现跨平台的关键,Java代码首先被编译成字节码文件,再由JVM将字节码文件翻译成机器语言,从而达到运行Java程序的目的。

注意:编译的结果不是生成机器码,而是生成字节码,字节码不能直接运行,必须通过JVM翻译成机器码才能运行。不同平台下编译生成的字节码是一样的,但是由JVM翻译成的机器码却不一样。

所以,运行Java程序必须有JVM的支持,因为编译的结果不是机器码,必须要经过JVM的再次翻译才能执行。即使你将Java程序打包成可执行文件(例如 .exe),仍然需要JVM的支持。

注意:跨平台的是Java程序,不是JVM。JVM是用C/C++开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的JVM。

2. Java中INT占几个字节

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
char 占2个字节
boolean 一个字节(1位)

3. Java面向对象的特征

封装、抽象、继承和多态。

封装:在面向对象语言中,封装特性是由类来体现的,我们将现实生活中的一类实体定义成类,其中包括属性和行为(在Java中就是方法).例如电脑,

抽象:抽象就是将一类实体的共同特性抽象出来,封装在一个抽象类中,所以抽象在面向对象语言是由抽象类来体现的。比如人.
class Person{}

继承:继承就像是我们现实生活中的父子关系,儿子可以遗传父亲的一些特性,在面向对象语言中,就是一个类可以继承另一个类的一些特性,从而可以代码重用.
eg:class Zhangsan extends Person{};

多态:多态就是通过传递给父类对象引用不同的子类对象从而表现出不同的行为
eg:Person person=new Zhangsan();

4. 装箱和拆箱

装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。

在这里插入图片描述

  1. Integer a = Integer.valueOf(123);//装箱
  2. int b = a.intValue(); //拆箱

5. ==和EQUALS的区别

关于==
1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(),比较的是他们的值。
2.复合数据类型(类) 当他们用(
)进行比较的时候,比较的是他们在内存中的存放地

关于equals

Java 语言里的 equals方法其实是交给开发者去覆写的,让开发者自己去定义满足什么条件的两个Object是equal的。

6.String,StringBuilder,StringBuffer的区别

运行速度:StringBuilder >StringBuffer >String

String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。而StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。

线程安全:StringBuilder是线程不安全的,而StringBuffer是线程安全的

如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。

使用场景

String:适用于少量的字符串操作的情况

StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况

StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

7. 讲一下JAVA中的集合

java中的集合分为value(Collection),和key-value(Map)两种;

存储value的有list和set两种:
list是有序的,可重复的
set是无序的,不可重复的

存储为key-value是map:HashMap,Hashtable,CurrentHashMap

8. ARRAYLIST, Vector和LINKEDLIST的区别

  1. 区别

Vector、ArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储。
Vector线程同步,ArrayList、LinkedList线程不同步。
LinkedList适合指定位置插入、删除操作,不适合查找;ArrayList、Vector适合查找,不适合指定位置的插入、删除操作。
Vector默认扩充为原来的两倍,(每次扩充空间的大小是可以设置的),而ArratList默认扩充为原来的1.5倍(查看之前的文章),因此ArrayList更节省空间。

  1. 联系

ArrayList,Vector、LinkedList类均在java.util包中都是可改变大小的.
ArrayList和Vector都是基于存储元素的Object[ ] array 来实现的,他们会在内存中开辟一块连续的空间来存储,由于数据存储是连续的,因此,他们支持用索引来访问元素,同时索引数据的速度比较快。但是在插入元素时需要移动容器中的元素,所以对数据的插入操作执行的比较慢。ArrayList和Vector都有一个初始化的容量大小,当里边存储的元素超过这个大小时就需要动态地扩充他们的存储空间。

9. HASHMAP和HASHTABLE的区别

相同:HashMap和Hashtable都可以使用来存储key-value的数据

区别:

基类不同:HashTable基于Dictionary类,而HashMap是基于AbstractMap。Dictionary是什么?它是任何可将键映射到相应值的类的抽象父类,而AbstractMap是基于Map接口的骨干实现,它以最大限度地减少实现此接口所需的工作。

线程安全:HashMap时单线程安全的,Hashtable是多线程安全的。

遍历不同:HashMap仅支持Iterator的遍历方式,Hashtable支持Iterator和Enumeration两种遍历方式。

null不同:HashMap可以允许存在一个为null的key和任意个为null的value,但是HashTable中的key和value都不允许为null。

多线程时,如何保障线程安全的同时也能保证效率?ConcurrentHashMap
通过把整个Map分为N个segment(类似Hashtable),这样既可以保障线程安全,也能使效率提高N倍,默认是16倍.
ConcurrentHashMap当中每个Segment各自持有一把锁。在保证线程安全的同时降低了锁的粒度,让并发操作效率更高。

10. 实现一个拷贝文件的工具类要使用字节流还是字符串

使用字节流,因为我们要拷贝的文件,不好确定里面是否全是字符,如果文件中包含图片之类的字节时,就需要使用字节流.所以,我们一般是用字节流拷贝文件.

11. 线程的的实现方式?怎么启动线程?怎么区分线程?

1.1.继承Thread类,不推荐
1.2 实现Runnable 接口
1.3 实现java.util.concurrent下的Callable接口

12. 线程并发库和线程池的作用

简单了解过,JDK5中增加了并发库,java.util.concurrent中提供了对线程优化.管理的各项操作,该包提供了线程的运行,线程池的创建,线程生命周期的控制.

线程池:java.util.concurrent.Executors创建四种线程池

newCachedThreadPool 创建非固定数量,可缓存的线程池,若线程池超过处理需要,可灵活回收空线程,若没有线程可回收,则建新线程
newFixedThreadPool固定线程池,底层是无界队列,可控制最大并发数,超出的线程会在队列中等待
newScheduledThreadPool定时执行线程池,支持定时及周期性任务执行
newSingleThreadExecutor单线程化的线程池,只会用唯一的工作线程来执行任务,保证所有任务按照顺序执行
线程池的好处:

限定线程的个数,不会导致由于线程过多导致系统运行缓慢或崩溃
线程池每次都不需要去创建和销毁,节约了资源
线程池不需要每次都去创建,相应时间更快.

13. 设计模式和常用的设计模式(选择自己熟悉的说,最好能手写)

设计过程中可以反复使用的、可以解决特定问题的通用模板。

创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

14. HTTP GET POST请求的区别

1、GET请求,请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接。URL的编码格式采用的是ASCII编码,而不是uniclde,即是说所有的非ASCII字符都要编码之后再传输。

POST请求:POST请求会把请求的数据放置在HTTP请求包的包体中。

因此,GET请求的数据会暴露在地址栏中,而POST请求则不会。

2、传输数据的大小

在HTTP规范中,没有对URL的长度和传输的数据大小进行限制。但是在实际开发过程中,对于GET,特定的浏览器和服务器对URL的长度有限制。因此,在使用GET请求时,传输数据会受到URL长度的限制。

对于POST,由于不是URL传值,理论上是不会受限制的,但是实际上各个服务器会规定对POST提交数据大小进行限制,Apache、IIS都有各自的配置。

3、安全性

POST的安全性比GET的高。这里的安全是指真正的安全,而不同于上面GET提到的安全方法中的安全,上面提到的安全仅仅是不修改服务器的数据。比如,在进行登录操作,通过GET请求,用户名和密码都会暴露再URL上,因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的用户名和密码就很容易被他人拿到了。

15. 说说你对SERVLET的理解

就是一个运行在WEB服务器上的小的Java程序,用来接收和响应从客户端发送过来的请求,通常使用HTTP协议.

使用:

1、编写一个Java类,实现servlet接口。

2、把开发好的Java类部署到web服务器中。

按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet

 Servlet            :接口
    |
 GenericServlet :通用的Servlet
    |
 HttpServlet        :HttpServlet

编写一个类继承HttpServlet,重写doGet和doPost方法.

  • 配置
  • 在这里插入图片描述

16. SERVLET的生命周期

用户第一次访问Servlet的时候,服务器会创建一个Servlet的实例,那么Servlet中init方法就会执行.任何一次请求服务器都会创建一个新的线程访问Servlet中的service的方法.在service方法内部根据请求的方式的不同调用doXXX的方法.(get请求调用doGet,post请求调用doPost).当Servlet中服务器中移除掉,或者关闭服务器,Servlet的实例就会被销毁,那么destroy方法就会执行.

17. SERVLET中FORWARD和REDIRECT的区别

重定向(redirect)其实是两次request,第一次,客户端request,A服务器响应,并response回来,告诉浏览器,你应该去B。这个时候IE可以看到地址变了,而且历史的回退按钮也亮了。重定向可以访问自己web应用以外的资源。在重定向的过程中,传输的信息会被丢失。
请求转发(forward)是服务器内部把对一个request/response的处理权,移交给另外一个.对于客户端而言,它只知道自己最早请求的那个A,而不知道中间的B,甚至C、D。传输的信息不会丢失。

18. JSP和SERVLET的相同点和不同点

联系:
JSP 是 Servlet 技术的扩展,本质上是 Servlet 的简易方式,更强调应用的外表表达。
JSP编译后是”类 servlet”。
不同点:

  • Servlet 的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。Servlet如果要实现html功能,必须使用Writer输出对应的html.
  • JSP 的情况是Java和HTML可以组合成一个扩展名为.jsp 的文件。做界面展示比较方便,而嵌入逻辑复杂.
  • JSP 侧重于视图,Servlet 主要用于控制逻辑

19. jsp内置对象和四大作用域和页面传值

内置对象名 类型
request HttpServletRequest
response HttpServletResponse
config ServletConfig
application ServletContext
session HttpSession
exception Throwable
page Object(this)
out JspWriter
pageContext PageContext
域 范围
page域 只能在当前jsp页面使用
request域 只能在同一个请求中使用
session域 只能在同一个会话(session对象)中使用
context域 只能在同一个web应用中使用

20. SESSION和COOKIE的区别和使用场景

Session和cookie都是会话(session)跟踪技术.cookie通过在客户端记录信息确定用户身份,而session是通过在服务器端记录信息确定用户身份.但是session的实现依赖于cookie机制来保存JESESSIONID(session的唯一标识,需要存在客户端)

区别:

cookie的数据存储在客户端,session的数据存储在服务器上
cookie不是很安全,别人可以通过分析存放在本地的cookie并进行cookie欺骗,考虑到安全应该使用session
session会在一定时间内保存在服务器上,当访问增多时,会影响服务器的性能.考虑到服务器性能,应当使用cookie.
单个cookie保存数据不能超过4k,很多浏览器显示一个站点最多保存20个cookie
将重要信息保存在session中(登陆),将其他需要保留的信心存放在cookie中(购物车,cookie是可以在客户端禁用的,这时候要使用cookie+数据库的方式实现购物车,当cookie中不能取出数据,就从数据库中取)

21. MVC模式和MVC各部分的实现

MVC的全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范.低耦合(m和v的分离)
struts2的mvc:jsp–>StrutsPrepareAndExecuteFilter(前端控制器,核心控制器)+action–>javabean–>result

22. 数据库分类和常用数据库

  • 关系型:MySQL、 ORACLE、SQL Server、IBM DB2、Sybase
  • 非关系型:Redis,Memcached,MongoDB ,Hadoop

23. 关系型数据库的三范式

范式就是规范,就是关系型数据库设计表时遵循的三个规范.要满足第二范式,必须先满足第一范式,要满足第三范式,必须先满足第二范式

1.第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。列数据的不可分割.
2.第二范式(2NF)要求数据库表中的每个实例或行必须可以被唯一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识.(主键)
3.第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。(外键)

反三范式:有时候为了效率,可以设置重复或者可推导出的字段.比如:订单(总价),订单项(单价)

24. 事务的四大特征

事务是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.例子:转账

事务的四大特性:ACID

1.原子性(Atomicity):表示事务内不可分割,要么都成功,要么都失败
2.一致性(Consistency):要么都成功,要么都失败.失败了,要对前面的操作进行回滚
3.隔离性(Isolation):一个事务开启了,不能受其它事务的影响
4.持久性(Durability):持续性,表示事务开始了,就不能终止.事务提交后,将数据序列化到数据库

25. MYSQL数据库最大连接数

数据库默认的最大连接数是100,在实际操作中,我们会去修改这个值:mysql安装文件–>my.ini文件

# The maximum amount of concurrent sessions the MySQL server will
# allow. One of these connections will be reserved for a user with
# SUPER privileges to allow the administrator to login even if the
# connection limit has been reached.
max_connections=100

26. MYSQL和ORACLE的分页语句

为什么要分页?很多数据不能完全展示出来,需要进行分段显示

mysql:是使用关键字limit来进行分页的.LIMIT [offset,] rows:offset指定要返回的第一行的偏移量(也就是从哪个索引开始),rows第二个指定返回行的最大数目。初始行的偏移量是0(不是1)
oracle:一般是使用rownum 加select 嵌套查询

27. 触发器的使用场景

触发器:触发器需要有触发条件,当条件满足后,做什么操作

应用场景:某些社交软件的日志更新,会通知好友; 一些论坛中,当插入新帖时,会更改当前帖子总数以及最后发帖时间.

CREATE [or REPLACE] TRIGGER 触发器名
BEFORE | AFTER
[DELETE ][[or] INSERT] [[or]UPDATE [OF 列名]]
ON 表名
[FOR EACH ROW ][WHEN(条件) ]
declare
……
begin
PLSQL 块
End ;

28. 存储过程的优点

1.存储过程只在创建时进行编译,以后每次执行它都不会再重新编译.一般SQL语句每次执行都会编译.所以存储过程会大大提高数据库执行速度
2.通常复杂的业务逻辑需要多条SQL语句,这些语句要分别从客户机发送到服务器,当客户机和服务器之间的操作很多时,会产生大量的网络传输.如果将这些操作放在一个3.存储过程中,那么客户机和服务器之间的网络传输会大大减少,降低网络负载.
4.存储过程是可重复使用的,能减少数据库开发人员的工作量.
5.存储过程可以屏蔽对底层数据对象的直接访问,使用EXECUTE权限调用存储过程,无需拥有访问底层数据库对象的显示权限,安全性高.

29. JDBC调用存储过程

加载驱
获取连接
设置参数
执行
释放连接

30. 简单说一下你对JDBC的理解

Java database connection java数据库连接,数据库关系系统很多,每个数据库关系管理系统支持的命令是不一样的.
Java只定义接口,让数据库厂商自己实现接口,对于我们开发人员而言,只需要导入对应厂商开发的实现即可,然后以接口的方式进行调用(mysql+mysql驱动(实现)+jdbc)

31. 写一个JDBC的访问ORACLE的列子

public class OracleUtils {
static {
    try {
        Class.forName("oracle.jdbc.driver.OracleDriver");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}
 
//获取连接
public static Connection getConnection() throws SQLException {                                                  
    Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@ip:1521:orcl", "username", "password");
    return conn;
 
}
//关闭资源
public static void close(ResultSet rs, Statement stmt, Connection conn) {
}
}
.....
调用
Connection conn = OracleUtils.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();
OracleUtils.close(rs, stmt, conn);

32. JDBC中PREPAREDSTATEMENT比STATEMENT的好处

PreparedStatement可以防止sql注入攻击,它是预编译的,

33. 数据库连接池的作用

限定数据库的连接个数,不会由于数据库连接过多导致系统运行缓慢或崩溃
数据库连接不需要每次都去创建或销毁,节约了资源
数据库连接不需要每次都去创建,响应时间更快.

34. 简单说一下HTML,CSS,JAVASCRIPT在网页开发中的定位

Html 超文本标记语言,定义网页的结构
Css 层叠样式表,用来美化页面
Javascript 主要用来验证表单,做动态交互(其中ajax)

35. 简单介绍了一下AJAX

什么是ajax?异步的javascript和xml
作用是什么?通过ajax与服务器进行数据交换,ajax可以使网页实现局部更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新.
怎么实现?ajax xmlhttpRrqueset对象,使用这个对象可以异步向服务器发送请求,获取响应,完成局部更新,open send responseText/responseXml局部响应.
使用场景:登陆失败时不跳转页面,注册时提示用户名是否存在,二级联动等等.

36. JS和JQUERY的关系

JQuery是一个js框架,封装了js的属性和方法,并且增强了js的功能,让用户使用起来更加便利,并且增强了js的功能.
原来是使用js是要处理很多兼容性的问题(比如注册事件等),由JQuery封装了底层,就不用处理兼容性问题.
原生的js的dom和事件绑定和ajax等操作非常麻烦,JQuery封装了以后,操作非常方便.

37. JQUERY中的常用选择器

ID选择器
Class选择器
标签选择器
通用选择器
层次选择器
属性选择器

38. JQUERY中页面加载完毕事件

为什么需要页面加载事件?很多时候我们需要获取元素,但是必须等到该元素被加载后才能获取,我们可以把js代码放到该元素的后面,但是这样就会造成js在我们的body中存在不好管理.所有页面加载完毕后,所有的元素当然已经加载完毕,一般获取元素做操作都要在页面加载完毕后.
$(function{}表示的是页面结构被加载完毕
Window.onload表示的是页面被加载完毕

39. JQUERY中AJAX和原生JS实现AJAX的关系

JQuery中的ajax也是通过原生的js封装的,封装完成后让我们使用起来更加便利,不用考虑底层实现或兼容性等的处理.
如果采用原生js实现ajax是非常麻烦的,并且每次都是一样的.如果我们不适用JQuery,我们也要封装对象的方法和属性,有像JQuery这些已经封装完成,经过很多企业实践过的框架,比较可靠,我们不需要封装,直接使用成熟的框架(JQuery)即可.

40. BOOTSTRAP的是什么

Bootstrap是一个移动设备优先的UI框架.我们不用写任何的css和js代码就能实现比较漂亮的有交互性的页面.我们程序员对页面的编写是有硬伤的,所以要自己写页面的话,就要使用类似bootstrap这样的UI框架.
平时经常用的:
模态框
表单,表单项
布局
栅格系统

41. 什么是框架

框架(Framework)是一个框子—–具有约束性,也是一个架子—-具有支撑性.
IT语境中的框架,特支为解决一个开放性问题而设计的具有一定约束性的支撑架构.在此结构上可以根据具体问题扩展.安插更多的组成部分.从而更迅速和更方便的构建完整的解决问题的方案.

框架本身一般不完整到可以解决特定问题,但是可以帮助我们快速解决特定问题
框架天生就是为了扩展而设计的
框架里面可以为后续扩展的组件提供很多辅助性,支撑性的方便易用的使用工具.也就是说框架时常配套; 一些帮助解决某类问题的库或工具.

42. 简单介绍一下MVC模式

MVC全名是model view Controller,是模型(model)—视图(view)—控制器(Controller)的缩写,是一种软件设计典范.
最简单的,最经典的就是jsp(view)+servlet(Controller)+javabean(model)
1.当控制器收到来自用户的请求
2.控制器调用javabean完成业务
3.完成业务后通过控制器跳转jsp页面的方式给用户反馈信息
4.Jsp给用户做出响应

43. 简单说一下对MVC框架的理解

是为了解决传统的MVC模式(jsp+servlet+javabean)问题而出现的框架.

传统MVC模式问题
1.所有的servlet和servlet映射都要配置在web.xml中,如果项目太大,web.xml就太庞大,并且不能实现模块化管理.
2.Servlet的主要功能就是接受参数,调用逻辑,跳转页面,比如像其他字符编码,文件上传等功能也要写在servlet中,不能让servlet功能单一.
3.接受参数比较麻烦,不能通过model接收,只能单个接收,接收完成后转换封装进model.
4.跳转页面方式比较单一(forward,redirect),并且当页面名称发生变化时,需要修改servlet源代码.

常用的MVC框架:struts2,springMVC

44. STRUTS2的执行流程或者STRUTS2的原理

1.浏览器发送请求,经过一系列的过filter,到达strutsPrepareAndExecuteFilter
2.strutsPrepareAndExecuteFilter通过ActionMapper判断当前的请求是否需要某个Action处理,如果不需要,则走原来的流程.如果需要,把请求交个ActionProxy来处理
3.ActionProxy通过Configuration Manager 询问框架的配置文件struts.xml,找到需要调用的Action类;
4.创建一个ActionInvocation实例,来调用Action的对应方法来获取结果集的name,在调用前后会执行相关拦截器
5/通过结果集的name找到对应的结果集来对浏览器进行响应

45. STRUTS2的拦截器是什么

通过动态配置方式,可以在执行Action的方法前后,加入相关逻辑,完成业务 .struts2中的功能, 都是通过系统拦截器实现的.比如:参数处理,文件上传,字符编码.当然,我们也可以自定义拦截器
使用场景:用户登陆判断,在执行Action的前面判断是否已经登陆,如果没有登陆则跳转到登陆页面;用户权限的判断,在执行Action的前面判断是否具有权限,如果没有给出提示信息;

46. SPRING MVC的执行流程

1.用户发送请求,被前端控制器(DispatcherServlet)捕获(捕获请求)
2.前端控制器进行解析,得到URI,通过URI调用HandlerMapping并获得该Handler配置的所有相关对象(查找Handler)
3.前端控制器根据得到的Handler,选择合适的HandlerAdapter,提取Request中的模型数据,填入Handler入参,开始执行Handler,最后返回一个ModelAndView对象.(执行Handler)
4.前端控制器根据返回的ModelAndViewm,选择合适的ViewResolver(选择ViewResolver)
5.通过ViewResolver结合Model和View来渲染视图,前端控制器将渲染结果返回给客户端(渲染并返回)

47. SPRINGMVC和STRUTS2的不同

核心控制器不同:springmvc是servlet,struts2是filter
控制器实例:springmvc会比struts快(理论上),springmvc是基于方法设计,struts是基于对象,每发一次请求都会实例一个action.springmvc只有一个实例,每次请求执行对应的方法即可,简单来说,springmvc是单例,是trust是多例
管理方式:springmvc是spring的一个模块,所以spring对于springmvc的控制管理更加简单方便.而struts需要使用xml配置很多参数来管理
参数传递:struts2中自身提供多种参数接收,其实都是通过valuestack进行传递和赋值.而springmvc是通过方法参数进行接收.
interceptor的实现机制:struts有自己的interceptor机制,springmvc用的是独立的aop方式.
Springmvc处理ajax请求,直接返回数据,方法中使用注解@ResponseBody,springmvc自动帮我们将数据转成json数据,而struts2是通过插件的方式进行处理

48. 简单介绍一下SPRING或者SPRING的两大核心

Spring是什么?spring是j2ee应用程序框架,是轻量级的IOC和AOP的容器框架,主要针对javabean的生命周期进行管理的轻量级容器,可以单独使用,也可以跟其它框架组合使用.

IOC(inversion of control)或DI(dependency injection)控制反转

原来:我的service要调用Dao,我就在service中创建Dao对象,这时Dao对象的创建的控制权在我手中

Spring:spring发现我的service依赖于Dao,就给我的service注入Dao对象,这时Dao对象创建的控制权在spring手中

核心原理:工厂模式+反射+配置文件

AOP:面向切面编程

核心原理:使用动态代理的方式在执行前后或出现异常后做相关逻辑.

我们主要使用AOP来做:

事务处理

权限判断

日志记录

49. AOP是什么?都用它做什么

AOP:面向切面编程
核心原理:使用动态代理的方式在执行前后或出现异常后做加入相关逻辑.
我们主要使用AOP来做:
事务处理 执行方法前,开启事务,执行方法后提交事务,出现异常后回滚事务
权限判断 在执行方法前,判断是否具有权限
日志记录 在执行方法前执行日志

50. SPRING事务的传播特性和隔离级别

事务的传播特性:多个事务存在是怎么处理的策略.

传播行为 意义
PROPAGATION_MANDATORY 表示该方法必须运行在一个事务中。如果当前没有事务正在发生,将抛出一个异常
PROPAGATION_NESTED 表示如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于封装事务进行提交或回滚。如果封装事务不存在,行为就像PROPAGATION_REQUIRES一样。
PROPAGATION_NEVER 表示当前的方法不应该在一个事务中运行。如果一个事务正在进行,则会抛出一个异常。
PROPAGATION_NOT_SUPPORTED 表示该方法不应该在一个事务中运行。如果一个现有事务正在进行中,它将在该方法的运行期间被挂起。
PROPAGATION_SUPPORTS 表示当前方法不需要事务性上下文,但是如果有一个事务已经在运行的话,它也可以在这个事务里运行。
PROPAGATION_REQUIRES_NEW 表示当前方法必须在它自己的事务里运行。一个新的事务将被启动,而且如果有一个现有事务在运行的话,则将在这个方法运行期间被挂起。
PROPAGATION_REQUIRES 表示当前方法必须在一个事务中运行。如果一个现有事务正在进行中,该方法将在那个事务中运行,否则就要开始一个新事务。

ISOLATION_DEFAULT 使用后端数据库默认的隔离级别。
ISOLATION_READ_UNCOMMITTED 允许读取尚未提交的更改。可能导致脏读、幻影读或不可重复读。
SOLATION_READ_COMMITTED 允许从已经提交的并发事务读取。可防止脏读,但幻影读和不可重复读仍可能会发生。
ISOLATION_REPEATABLE_READ 对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻影读仍可能发生。
ISOLATION_SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。

51. ORM是什么?ORM框架是什么?

对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单来说,将程序中的兑现自动持久化到关系数据库中。那么,到底如何实现持久化呢?一种简单的反感是采用硬编码的方式(jdbc操作sql方式),为每一种可能的数据库访问操作提供单独的方法。这种方法存在很多缺陷,所以使用ORM框架(为了解决面型对象与关系数据库存在的互不匹配的现象的框架)来解决。

Java典型的ORM框架有:Hibernate,mybatits

52. WEBSERVICE的使用场景

Webservice是一个SOA(面向服务的编程)的架构,它是不依赖于语言,不依赖于平台,可以实现不同的语言间的相互调用,通过Internet进行基于http协议的网络应用间的交互.

异构系统(语言)的整合
不同客户端的整合,浏览器 手机端 pc端等终端的访问
例子:
天气预报:可以通过实现webservice客户端调用远程天气服务实现的.
单点登录:一个服务器实现所有系统的登陆

53. ACTIVITI的简单介绍

Activiti是一个业务流程管理(BPM)和工作流系统,适用于开发人员和系统管理人员,其核心是超快速,稳定的BPMN2流程引擎,它易与spring集成使用.
主要用在OA中,把线下流程放到线上,把现实生活中的一些流程固话定义到系统中,然后通过输入表单数据完成业务.

54. LINUX的使用场景

Linux是一个长时间运行比较稳定的操作系统,所以我们一般会拿它作为服务器(web,db.app等).
Linux本身具有c的编译环境.我们的一些软件是没有软件包的(redis,nginx),需要在linux编译得到软件包

55. LINUX常用命令

Cd跳转到目录
Pwd 获取当前路径
Su 切换用户
Ll 查看当前目录下文件和目录
Tail 查看文件
Rm –rf 删除文件
Vi 修改文件
Mv 移动/重命名 文件或文件夹
Mkdir 创建文件夹
Rm –f 删除文件夹
Tar 打包/解压
Grep 查找想要的信息

56. 怎么操作LINUX服务器

需要依赖于linux服务器安装ssh服务端,一般这个ssh服务的端口为22,
需要依赖于linux服务器安装sftp服务端,一般这个sftp服务的端口为25,

使用ssh客户端连接linux服务器,通过命令操作linux服务器
使用sftp客户端来连接sftp服务端,来上传和下载文件(安装包,修改文件上传)

57. 有没有使用过云主机

使用过阿里云
云主机:就是一些云服务运营商(阿里,华为,新浪等)提供的远程服务器功能,我们公司只要付费就可以租用对应的服务器.

58. 数据库优化方面的事情

定位:查找,定位慢查询,并优化
优化
1.创建索引:创建合适的索引,我们就可以在索引中查询,查询到以后直接找对应的额记录
2,分表:当一张表的数据比较多或者一张表的某些字段的值比较多并且很少使用时,采用水平分表或垂直分表来优化,比如spu表
3,读写分离:当一台服务器不能满足需要时,采用将读写分离的方式进行集群
4.缓存:使用redis来进行缓存

59. 选择合适的索引

索引是帮助DBMS高效获取数据的数据结构.
分类:普通索引,唯一索引,主键索引,全文索引
1.普通索引:允许重复的值出现
2.唯一索引:除了不能有重复的记录外,其它和普通索引一样.(用户名;用户身份证;手机号)
3.主键索引:是随着设定主键而创建的;也就是把某个列设为主键的时候,数据库就会给该列创建索引;唯一且没有null值
4.全文索引:用来对表中文本域(char,varchar,text)进行索引,全文索引针对myisam

60. 使用索引的一些技巧

索引弊端:

  1. 占用磁盘空间.
  2. 对dml(插入,修改.删除)操作有影响,变慢
    使用场景:
  3. 肯定在where条件经常使用,如果不做查询就没有意义
  4. 该字段的内容不是唯一的几个值(sex).
  5. 字段内容不是频繁变化

61. 项目的并发

1.需求:用户量,这个客户说了算,大概也就是1-5年内用户总量
2.根据pv(页面点击量,浏览量)和uv(ip数量)预估,大致能达到多大的并发量.我们的项目大概能达到1000-3000的并发量
3.确定我们的服务器数量,我们使用的是tomcat,tomcat的默认线程数150,我们可以将它优化调到400左右.而我们大致需要5台web服务器
4.重要的因素(硬件服务器水平—去IOE),我们没有做这个,因为我们没钱.

62. http协议

1.无状态,为了解决http无状态问题,引入cookie技术
2.http1.0是短连接,http1.1是长连接
3.http协议是基于B/S请求-应答模式

63. cookie和session

1.Cookie是由服务器创建的,通过response对象的addCookie(Cookie cookie)方法写回客户端,存储在客户端的会话技术.key-value的结构
2.session是基于cookie,session的创建是由服务器做,可以通过request.getSession()获取(要从你的请求中找一个cookie—Jessionid,如果能找到这个cookie,他会拿着这个cookie的值去跟服务器端的session的id比较,如果找到相应的session,就不创建session.如果找不到相应的session,会创建session).session一旦创建就会有一个id属性(唯一的),通过response以cookie的方式写回客户端(这个cookie就叫做就sessionid).

会话:会话就是简单的理解成打开浏览器(包含了一次请求或多次请求).

64. session共享的方案

1.广播:会造成内网网络风暴,大量占用内网宽带
2.IP_hash:在nginx中配置和,相同的ip找固定的同一台服务器,这种方案会造成服务能力差
3.使用第三方中间件(数据库,redis),我们是使用redis

65. 高并发问题:索引库同步

1.硬编码:在相应的代码中增加索引库同步的代码。不过,这种方法耦合度太高,将原本不相关的系统耦合在了一起,容易造成不可预估的错误,是电商项目的大忌。
2.spring的aop:编写一个索引库同步的方法,利用aop的形式,将它和数据库数据更新的方法联系起来。这种方式也会造成耦合。
3.消息队列:不过,这个方法会造成一个问题,那就是消息消费失败问题。

66. 单点登录的核心是什么

单点登录的核心是如何在多个系统之间共享身份信息

67. solr 的索引查询为什么比数据库要快

Solr 使用的是 Lucene API 实现的全文检索。全文检索本质上是查询的索引。而数据库中并
不是所有的字段都建立的索引,更何况如果使用 like 查询时很大的可能是不使用索引,所以
使用 solr 查询时要比查数据库快。

68. solr 索引库个别数据索引丢失怎么办

首先 Solr 是不会丢失个别数据的。如果索引库中缺少数据,那就向索引库中添加

69. IO和NIO

IO NIO
面向流 面向缓冲
阻塞IO 非阻塞IO
无 选择器

70.https和http

HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。

71.TCP和UDP的区别

1.tcp面向连接(如打电话要先拨号连接);udp是无连接的,即发送数据之前不需要连接
2.tcp提供可靠的服务。也就是说通过tcp传送的数据,无差错,无丢失,不重复,且按序到达;udp尽最大努力交付,不保证交付是否成功
3.tcp面下字节流,实际上tcp把数据看成是一连串无结构的字节流;udp是面向报文的,udp没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,比如视频会议)
4.每一条tcp连接只能是点到点的;udp支持一对一,一对多,多对一,多对多的交互通信
5.tcp首部开销20字节;udp首部开销小,只有8字节
6.tcp通信信道是全双工的可靠信道;udp则是不可靠

72.访问修饰符public,private,protected,以及不写(默认)时的区别?

在这里插入图片描述
protected 当前类,同包,异包子类。

73.float f=3.4;是否正确?

答:不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;

74.short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?

答:对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给short型。而short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 = (short)(s1 + 1);其中有隐含的强制类型转换。

75.Java有没有goto?

答:goto 是Java中的保留字,在目前版本的Java中没有使用。(根据James Gosling(Java之父)编写的《The Java Programming Language》一书的附录中给出了一个Java关键字列表,其中有goto和const,但是这两个是目前无法使用的关键字,因此有些地方将其称之为保留字,其实保留字这个词应该有更广泛的意义,因为熟悉C语言的程序员都知道,在系统类库中使用过的有特殊意义的单词或单词的组合都被视为保留字)

76.int和Integer有什么区别?

答:Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型(wrapper class),int的包装类就是Integer,从Java 5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。
Java 为每个原始类型提供了包装类型:

原始类型: boolean,char,byte,short,int,long,float,double
包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double

77.&和&&的区别?

答:&运算符有两种用法:(1)按位与;(2)逻辑与。&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是true。&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是null而且不是空字符串,应当写为:username != null &&!username.equals(""),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生NullPointerException异常。注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。

78.解释内存中的栈(stack)、堆(heap)和方法区(method area)的用法。

答:通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用JVM中的栈空间;而通过new关键字和构造器创建的对象则放在堆空间,堆是垃圾收集器管理的主要区域,由于现在的垃圾收集器都采用分代收集算法,所以堆空间还可以细分为新生代和老生代,再具体一点可以分为Eden、Survivor(又可分为From Survivor和To Survivor)、Tenured;方法区和堆都是各个线程共享的内存区域,用于存储已经被JVM加载的类信息、常量、静态变量、JIT编译器编译后的代码等数据;程序中的字面量(literal)如直接书写的100、"hello"和常量都是放在常量池中,常量池是方法区的一部分,。栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,栈和堆的大小都可以通过JVM的启动参数来进行调整,栈空间用光了会引发StackOverflowError,而堆和常量池空间不足则会引发OutOfMemoryError。

String str = new String(“hello”);

上面的语句中变量str放在栈上,用new创建出来的字符串对象放在堆上,而"hello"这个字面量是放在方法区的。

补充1:较新版本的Java(从Java 6的某个更新开始)中,由于JIT编译器的发展和"逃逸分析"技术的逐渐成熟,栈上分配、标量替换等优化技术使得对象一定分配在堆上这件事情已经变得不那么绝对了。

补充2:运行时常量池相当于Class文件常量池具有动态性,Java语言并不要求常量一定只有编译期间才能产生,运行期间也可以将新的常量放入池中,String类的intern()方法就是这样的。

看看下面代码的执行结果是什么并且比较一下Java 7以前和以后的运行结果是否一致。

String s1 = new StringBuilder("go")
    .append("od").toString();
System.out.println(s1.intern() == s1);
String s2 = new StringBuilder("ja")
    .append("va").toString();
System.out.println(s2.intern() == s2);

79.Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?

答:Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整。

80.switch 是否能作用在byte 上,是否能作用在long 上,是否能作用在String上?

答:在Java 5以前,switch(expr)中,expr只能是byte、short、char、int。从Java 5开始,Java中引入了枚举类型,expr也可以是enum类型,从Java 7开始,expr还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。

81.用最有效率的方法计算2乘以8?

答: 2 << 3(左移3位相当于乘以2的3次方,右移3位相当于除以2的3次方)。

补充:我们为编写的类重写hashCode方法时,可能会看到如下所示的代码,其实我们不太理解为什么要使用这样的乘法运算来产生哈希码(散列码),而且为什么这个数是个素数,为什么通常选择31这个数?前两个问题的答案你可以自己百度一下,选择31是因为可以用移位和减法运算来代替乘法,从而得到更好的性能。说到这里你可能已经想到了:31 * num 等价于(num << 5) - num,左移5位相当于乘以2的5次方再减去自身就相当于乘以31,现在的VM都能自动完成这个优化。

82.数组有没有length()方法?String有没有length()方法?

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

83.在Java中,如何跳出当前的多重嵌套循环?

答:在最外层循环前加一个标记如A,然后用break A;可以跳出多重循环。(Java中支持带标签的break和continue语句,作用有点类似于C和C++中的goto语句,但是就像要避免使用goto一样,应该避免使用带标签的break和continue,因为它不会让你的程序变得更优雅,很多时候甚至有相反的作用,所以这种语法其实不知道更好)

84.构造器(constructor)是否可被重写(override)?

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

85.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?

答:不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同。当然,你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。

86.是否可以继承String类?

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

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

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

答:是按值传递。Java语言的方法调用只支持参数的按值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但在方法内部对对象引用的改变是不会影响到被调用者的。C++和C#中可以通过传引用或传输出参数来改变传入的参数的值。在C#中可以编写如下所示的代码,但是在Java中却做不到。

88.重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?

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

89.描述一下JVM加载class文件的原理机制?

答:JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件中的类。
由于Java的跨平台性,经过编译的Java源程序并不是一个可执行程序,而是一个或多个类文件。当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的Class对象。加载完成后,Class对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后JVM对类进行初始化,包括:1)如果类存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;2)如果类中存在初始化语句,就依次执行这些初始化语句。
类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)。从Java 2(JDK 1.2)开始,类加载过程采取了父亲委托机制(PDM)。PDM更好的保证了Java平台的安全性,在该机制中,JVM自带的Bootstrap是根加载器,其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器加载,父类加载器无能为力时才由其子类加载器自行加载。JVM不会向Java程序提供对Bootstrap的引用。下面是关于几个类加载器的说明:

Bootstrap:一般用本地代码实现,负责加载JVM基础核心类库(rt.jar);
Extension:从java.ext.dirs系统属性所指定的目录中加载类库,它的父加载器是Bootstrap;
System:又叫应用类加载器,其父类是Extension。它是应用最广泛的类加载器。它从环境变量classpath或者系统属性java.class.path所指定的目录中加载类,是用户自定义加载器的默认父加载器。

90.char 型变量中能不能存贮一个中文汉字,为什么?

答:char类型可以存储一个中文汉字,因为Java中使用的编码是Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的唯一方法),一个char类型占2个字节(16比特),所以放一个中文是没问题的。

补充:使用Unicode意味着字符在JVM内部和外部有不同的表现形式,在JVM内部都是Unicode,当这个字符被从JVM内部转移到外部时(例如存入文件系统中),需要进行编码转换。所以Java中有字节流和字符流,以及在字符流和字节流之间进行转换的转换流,如InputStreamReader和OutputStreamReader,这两个类是字节流和字符流之间的适配器类,承担了编码转换的任务;对于C程序员来说,要完成这样的编码转换恐怕要依赖于union(联合体/共用体)共享内存的特征来实现了。

91.静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同?

答:Static Nested Class是被声明为静态(static)的内部类,它可以不依赖于外部类实例被实例化。而通常的内部类需要在外部类实例化后才能实例化

92.抽象类(abstract class)和接口(interface)有什么异同?

答:抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。接口比抽象类更加抽象,因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。

93.Java 中会存在内存泄漏吗,请简单描述。

答:理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因);然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生。例如Hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。

94.抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?

答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。

95.阐述静态变量和实例变量的区别。

答:静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。

96.是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?

答:不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在调用静态方法时可能对象并没有被初始化。

97.如何实现对象克隆?

答:有两种方式:
  1). 实现Cloneable接口并重写Object类中的clone()方法;
  2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,

98.GC是什么?为什么要有GC?

答:GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显式操作方法。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM可以屏蔽掉显式的垃圾回收调用。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。

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

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

100.接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?

答:接口可以继承接口,而且支持多重继承。抽象类可以实现(implements)接口,抽象类可继承具体类也可以继承抽象类。
举一个多继承的例子,我们定义一个动物(类)既是狗(父类1)也是猫(父类2),两个父类都有“叫”这个方法。那么当我们调用“叫”这个方法时,它就不知道是狗叫还是猫叫了,这就是多重继承的冲突。
而接口没有具体的方法实现,所以多继承接口也不会出现这种冲突。

101.一个".java"源文件中是否可以包含多个类(不是内部类)?有什么限制?

答:可以,但一个源文件中最多只能有一个公开类(public class)而且文件名必须和公开类的类名完全保持一致。

102.Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口?

答:可以继承其他类或实现其他接口,在Swing编程和Android开发中常用此方式来实现事件监听和回调。

103.内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制?

答:一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。

104.数据类型之间的转换:

如何将字符串转换为基本数据类型?

如何将基本数据类型转换为字符串?

答:

调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型;
一种方法是将基本数据类型与空字符串("")连接(+)即可获得其所对应的字符串;另一种方法是调用String 类中的valueOf()方法返回相应字符串

105.如何实现字符串的反转及替换?

答:方法很多,可以自己写实现也可以使用String或StringBuffer/StringBuilder中的方法。有一道很常见的面试题是用递归实现字符串反转,

106.怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串?

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

107.日期和时间: 如何取得年月日、小时分钟秒? 如何取得从1970年1月1日0时0分0秒到现在的毫秒数? 如何取得某月的最后一天? 如何格式化日期?

答:
问题1:创建java.util.Calendar 实例,调用其get()方法传入不同的参数即可获得参数所对应的值。Java 8中可以使用java.time.LocalDateTimel来获取,

108.比较一下Java和JavaSciprt

答:JavaScript 与Java是两个公司开发的不同的两个产品。Java 是原Sun Microsystems公司推出的面向对象的程序设计语言,特别适合于互联网应用程序开发;而JavaScript是Netscape公司的产品,为了扩展Netscape浏览器的功能而开发的一种可以嵌入Web页面中运行的基于对象和事件驱动的解释性语言。JavaScript的前身是LiveScript;而Java的前身是Oak语言。
下面对两种语言间的异同作如下比较:

基于对象和面向对象:Java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象;JavaScript是种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件。它是一种基于对象(Object-Based)和事件驱动(Event-Driven)的编程语言,因而它本身提供了非常丰富的内部对象供设计人员使用。
解释和编译:Java的源代码在执行之前,必须经过编译。JavaScript是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行。(目前的浏览器几乎都使用了JIT(即时编译)技术来提升JavaScript的运行效率)
强类型变量和弱类型变量:Java采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量是弱类型的,甚至在使用变量前可以不作声明,JavaScript的解释器在运行时检查推断其数据类型。
代码格式不一样。

109.什么时候用断言(assert)?

答:断言在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。一般来说,断言用于保证程序最基本、关键的正确性。断言检查通常在开发和测试时开启。为了保证程序的执行效率,在软件发布后断言检查通常是关闭的。断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为true;如果表达式的值为false,那么系统会报告一个AssertionError。断言的使用如下面的代码所示:

110.Error和Exception有什么区别?

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

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

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

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

112.Java语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?

答:Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java中,每个异常都是一个对象,它是Throwable类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并可以对其进行处理。Java的异常处理是通过5个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果系统会抛出(throw)一个异常对象,可以通过它的类型来捕获(catch)它,或通过总是执行代码块(finally)来处理;try用来指定一块预防所有异常的程序;catch子句紧跟在try块后面,用来指定你想要捕获的异常的类型;throw语句用来明确地抛出一个异常;throws用来声明一个方法可能抛出的各种异常(当然声明异常时允许无病呻吟);finally为确保一段代码不管发生什么异常状况都要被执行;try语句可以嵌套,每当遇到一个try语句,异常的结构就会被放入异常栈中,直到所有的try语句都完成。如果下一级的try语句没有对某种异常进行处理,异常栈就会执行出栈操作,直到遇到有处理这种异常的try语句或者最终将异常抛给JVM。

113.运行时异常与受检异常有何异同?

答:异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常。异常和继承一样,是面向对象程序设计中经常被滥用的东西,在Effective Java中对异常的使用给出了以下指导原则:

不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
对可以恢复的情况使用受检异常,对编程错误使用运行时异常
避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
优先使用标准的异常
每个方法抛出的异常都要有文档
保持异常的原子性
不要在catch中忽略掉捕获到的异常

114.列出一些你常见的运行时异常?

答:

ArithmeticException(算术异常)
ClassCastException (类转换异常)
IllegalArgumentException (非法参数异常)
IndexOutOfBoundsException (下标越界异常)
NullPointerException (空指针异常)
SecurityException (安全异常)

115.阐述final、finally、finalize的区别。

答:

final:修饰符(关键字)有三种用法:如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词。将变量声明为final,可以保证它们在使用中不被改变,被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。被声明为final的方法也同样只能使用,不能在子类中被重写。
finally:通常放在try…catch…的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。
finalize:Object类中定义的方法,Java中允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize()方法可以整理系统资源或者执行其他清理工作。

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

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

117.阐述ArrayList、Vector、LinkedList的存储性能和特性。

答:ArrayList 和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector中的方法由于添加了synchronized修饰,因此Vector是线程安全的容器,但性能上较ArrayList差,因此已经是Java中的遗留容器。LinkedList使用双向链表实现存储(将内存中零散的内存单元通过附加的引用关联起来,形成一个可以按序号索引的线性结构,这种链式存储方式与数组的连续存储方式相比,内存的利用率更高),按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。Vector属于遗留容器(Java早期的版本中提供的容器,除此之外,Hashtable、Dictionary、BitSet、Stack、Properties都是遗留容器),已经不推荐使用,但是由于ArrayList和LinkedListed都是非线程安全的,如果遇到多个线程操作同一个容器的场景,则可以通过工具类Collections中的synchronizedList方法将其转换成线程安全的容器后再使用(这是对装潢模式的应用,将已有对象传入另一个类的构造器中创建新的对象来增强实现)。

118.Collection和Collections的区别?

答:Collection是一个接口,它是Set、List等容器的父接口;Collections是个一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。

119. List、Map、Set三个接口存取元素时,各有什么特点?

答:List以特定索引来存取元素,可以有重复元素。Set不能存放重复元素(用对象的equals()方法来区分元素是否重复)。Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一。Set和Map容器都有基于哈希存储和排序树的两种实现版本,基于哈希存储的版本理论存取时间复杂度为O(1),而基于排序树版本的实现在插入或删除元素时会按照元素或元素的键(key)构成排序树从而达到排序和去重的效果。

120.TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素?

答:TreeSet要求存放的对象所属的类必须实现Comparable接口,该接口提供了比较元素的compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap要求存放的键值对映射的键必须实现Comparable接口从而根据键对元素进行排序。Collections工具类的sort方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象必须实现Comparable接口以实现元素的比较;第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator接口的子类型(需要重写compare方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java中对函数式编程的支持)。

121.Thread类的sleep()方法和对象的wait()方法都可以让线程暂停执行,它们有什么区别?

答:sleep()方法(休眠)是线程类(Thread)的静态方法,调用此方法会让当前线程暂停执行指定的时间,将执行机会(CPU)让给其他线程,但是对象的锁依然保持,因此休眠时间结束后会自动恢复(线程回到就绪状态,请参考第66题中的线程状态转换图)。wait()是Object类的方法,调用对象的wait()方法导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify()方法(或notifyAll()方法)时才能唤醒等待池中的线程进入等锁池(lock pool),如果线程重新获得对象的锁就可以进入就绪状态。

122.线程的sleep()方法和yield()方法有什么区别?

答:
① sleep()方法给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会;yield()方法只会给相同优先级或更高优先级的线程以运行的机会;
② 线程执行sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪(ready)状态;
③ sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常;
④ sleep()方法比yield()方法(跟操作系统CPU调度相关)具有更好的可移植性。

123.当一个线程进入一个对象的synchronized方法A之后,其它线程是否可进入此对象的synchronized方法B?

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

124.请说出与线程同步以及线程调度相关的方法。

答:

wait():使一个线程处于等待(阻塞)状态,并且释放所持有的对象的锁;
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理InterruptedException异常;
notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且与优先级无关;
notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;

125.编写多线程程序有几种实现方式?

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

126.synchronized关键字的用法?

答:synchronized关键字可以将对象或者方法标记为同步,以实现对对象和方法的互斥访问,可以用synchronized(对象) { … }定义同步代码块,或者在声明方法时将synchronized作为方法的修饰符。在第60题的例子中已经展示了synchronized关键字的用法。

127.举例说明同步和异步。

答:如果系统中存在临界资源(资源数量少于竞争资源的线程数量的资源),例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就必须进行同步存取(数据库操作中的排他锁就是最好的例子)。当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。事实上,所谓的同步就是指阻塞式操作,而异步就是非阻塞式操作。

128.启动一个线程是调用run()还是start()方法?

答:启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM 调度并执行,这并不意味着线程就会立即运行。run()方法是线程启动后要进行回调(callback)的方法。

129.什么是线程池(thread pool)?

答:在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁,这就是”池化资源”技术产生的原因。线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。
Java 5+中的Executor接口定义一个执行线程的工具。它的子类型即线程池接口是ExecutorService。要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,因此在工具类Executors里面提供了一些静态工厂方法,生成一些常用的线程池,如下所示:

newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

130.简述synchronized 和java.util.concurrent.locks.Lock的异同?

答:Lock是Java 5以后引入的新的API,和关键字synchronized相比主要相同点:Lock 能完成synchronized所实现的所有功能;主要不同点:Lock有比synchronized更精确的线程语义和更好的性能,而且不强制性的要求一定要获得锁。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且最好在finally 块中释放(这是释放外部资源的最好的地方)。

131.Java中如何实现序列化,有什么意义?

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

132.Java中有几种类型的流?

答:字节流和字符流。字节流继承于InputStream、OutputStream,字符流继承于Reader、Writer。在 java.io 包中还有许多其他的流,主要是为了提高性能和使用方便。关于Java的I/O需要注意的有两点:一是两种对称性(输入和输出的对称性,字节和字符的对称性);二是两种设计模式(适配器模式和装潢模式)。另外Java中的流不同于C#的是它只有一个维度一个方向。

133.写一个方法,输入一个文件名和一个字符串,统计这个字符串在这个文件中出现的次数。

import java.io.BufferedReader;
import java.io.FileReader;
 
public final class MyUtil {
 
    // 工具类中的方法都是静态方式访问的因此将构造器私有不允许创建对象(绝对好习惯)
    private MyUtil() {
        throw new AssertionError();
    }
 
    /**
     * 统计给定文件中给定字符串的出现次数
     * 
     * @param filename  文件名
     * @param word 字符串
     * @return 字符串在文件中出现的次数
     */
    public static int countWordInFile(String filename, String word) {
        int counter = 0;
        try (FileReader fr = new FileReader(filename)) {
            try (BufferedReader br = new BufferedReader(fr)) {
                String line = null;
                while ((line = br.readLine()) != null) {
                    int index = -1;
                    while (line.length() >= word.length() && (index = line.indexOf(word)) >= 0) {
                        counter++;
                        line = line.substring(index + word.length());
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return counter;
    }
 
}

134.如何用Java代码列出一个目录下所有的文件?

import java.io.File;
 
class Test12 {
 
    public static void main(String[] args) {
        File f = new File("/Users/nnngu/Downloads");
        for(File temp : f.listFiles()) {
            if(temp.isFile()) {
                System.out.println(temp.getName());
            }
        }
    }
}

135.XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式?

答:XML文档定义分为DTD和Schema两种形式,二者都是对XML语法的约束,其本质区别在于Schema本身也是一个XML文件,可以被XML解析器解析,而且可以为XML承载的数据定义类型,约束能力较之DTD更强大。对XML的解析主要有DOM(文档对象模型,Document Object Model)、SAX(Simple API for XML)和StAX(Java 6中引入的新的解析XML的方式,Streaming API for XML),其中DOM处理大型文件时其性能下降的非常厉害,这个问题是由DOM树结构占用的内存较多造成的,而且DOM解析方式必须在解析文件之前把整个文档装入内存,适合对XML的随机访问(典型的用空间换取时间的策略);SAX是事件驱动型的XML解析方式,它顺序读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过事件回调代码来处理XML文件,适合对XML的顺序访问;顾名思义,StAX把重点放在流上,实际上StAX与其他解析方式的本质区别就在于应用程序能够把XML作为一个事件流来处理。将XML作为一组事件来处理的想法并不新颖(SAX就是这样做的),但不同之处在于StAX允许应用程序代码把这些事件逐个拉出来,而不用提供在解析器方便时从解析器中接收事件的处理程序。

136.阐述JDBC操作数据库的步骤

加载驱动。
创建连接。
创建语句。
执行语句。
处理结果。
关闭资源。

137.Statement和PreparedStatement有什么区别?哪个性能更好?

答:与Statement相比,①PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性);②PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全;③当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快(不用再次编译和生成执行计划)。

138.使用JDBC操作数据库时,如何提升读取数据的性能?如何提升更新数据的性能?

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

139.什么是DAO模式?

答:DAO(Data Access Object)顾名思义是一个为数据库或其他持久化机制提供了抽象接口的对象,在不暴露底层持久化方案实现细节的前提下提供了各种数据访问操作。在实际的开发中,应该将所有对数据源的访问操作进行抽象化后封装在一个公共API中。用程序设计语言来说,就是建立一个接口,接口中定义了此应用程序中将会用到的所有事务方法。在这个应用程序中,当需要和数据源进行交互的时候则使用这个接口,并且编写一个单独的类来实现这个接口,在逻辑上该类对应一个特定的数据存储。DAO模式实际上包含了两个模式,一是Data Accessor(数据访问器),二是Data Object(数据对象),前者要解决如何访问数据的问题,而后者要解决的是如何用对象封装数据。

140.JDBC中如何进行事务处理?

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

141.简述正则表达式及其用途。

答:在编写处理字符串的程序时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。

142.Java中是如何支持正则表达式操作的?

答:Java中的String类提供了支持正则表达式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。此外,Java中可以用Pattern类表示正则表达式对象,它提供了丰富的API进行各种正则表达式操作

143.获得一个类的类对象有哪些方式?

方法1:类型.class,例如:String.class
方法2:对象.getClass(),例如:“hello”.getClass()
方法3:Class.forName(),例如:Class.forName(“java.lang.String”)

144.如何通过反射创建对象?

方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance()
方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance(“Hello”);

145.如何通过反射获取和设置对象私有字段的值?

答:可以通过类对象的getDeclaredField()方法获得字段(Field)对象,然后再通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过get/set方法来获取/设置字段的值了。下面的代码实现了一个反射的工具类,其中的两个静态方法分别用于获取和设置私有字段的值,字段可以是基本类型也可以是对象类型且支持多级对象操作,例如ReflectionUtil.get(dog, “owner.car.engine.id”);可以获得dog对象的主人的汽车的引擎的ID号。

146.简述一下面向对象的"六原则一法则"。

答:

单一职责原则:一个类只做它该做的事情。(单一职责原则想表达的就是"高内聚",写代码最终极的原则只有六个字"高内聚、低耦合",就如同葵花宝典或辟邪剑谱的中心思想就八个字"欲练此功必先自宫",所谓的高内聚就是一个代码模块只完成一项功能,在面向对象中,如果只让一个类完成它该做的事,而不涉及与它无关的领域就是践行了高内聚的原则,这个类就只有单一职责。我们都知道一句话叫"因为专注,所以专业",一个对象如果承担太多的职责,那么注定它什么都做不好。这个世界上任何好的东西都有两个特征,一个是功能单一,好的相机绝对不是电视购物里面卖的那种一个机器有一百多种功能的,它基本上只能照相;另一个是模块化,好的自行车是组装车,从减震叉、刹车到变速器,所有的部件都是可以拆卸和重新组装的,好的乒乓球拍也不是成品拍,一定是底板和胶皮可以拆分和自行组装的,一个好的软件系统,它里面的每个功能模块也应该是可以轻易的拿到其他系统中使用的,这样才能实现软件复用的目标。)

开闭原则:软件实体应当对扩展开放,对修改关闭。(在理想的状态下,当我们需要为一个软件系统增加新功能时,只需要从原来的系统派生出一些新类就可以,不需要修改原来的任何一行代码。要做到开闭有两个要点:①抽象是关键,一个系统中如果没有抽象类或接口系统就没有扩展点;②封装可变性,将系统中的各种可变因素封装到一个继承结构中,如果多个可变因素混杂在一起,系统将变得复杂而混乱,如果不清楚如何封装可变性,可以参考《设计模式精解》一书中对桥梁模式的讲解的章节。)

依赖倒转原则:面向接口编程。(该原则说得直白和具体一些就是声明方法的参数类型、方法的返回类型、变量的引用类型时,尽可能使用抽象类型而不用具体类型,因为抽象类型可以被它的任何一个子类型所替代,请参考下面的里氏替换原则。)
里氏替换原则:任何时候都可以用子类型替换掉父类型。(关于里氏替换原则的描述,Barbara Liskov女士的描述比这个要复杂得多,但简单的说就是能用父类型的地方就一定能使用子类型。里氏替换原则可以检查继承关系是否合理,如果一个继承关系违背了里氏替换原则,那么这个继承关系一定是错误的,需要对代码进行重构。例如让猫继承狗,或者狗继承猫,又或者让正方形继承长方形都是错误的继承关系,因为你很容易找到违反里氏替换原则的场景。需要注意的是:子类一定是增加父类的能力而不是减少父类的能力,因为子类比父类的能力更多,把能力多的对象当成能力少的对象来用当然没有任何问题。)

接口隔离原则:接口要小而专,绝不能大而全。(臃肿的接口是对接口的污染,既然接口表示能力,那么一个接口只应该描述一种能力,接口也应该是高度内聚的。例如,琴棋书画就应该分别设计为四个接口,而不应设计成一个接口中的四个方法,因为如果设计成一个接口中的四个方法,那么这个接口很难用,毕竟琴棋书画四样都精通的人还是少数,而如果设计成四个接口,会几项就实现几个接口,这样的话每个接口被复用的可能性是很高的。Java中的接口代表能力、代表约定、代表角色,能否正确的使用接口一定是编程水平高低的重要标识。)

合成聚合复用原则:优先使用聚合或合成关系复用代码。(通过继承来复用代码是面向对象程序设计中被滥用得最多的东西,因为所有的教科书都无一例外的对继承进行了鼓吹从而误导了初学者,类与类之间简单的说有三种关系,Is-A关系、Has-A关系、Use-A关系,分别代表继承、关联和依赖。其中,关联关系根据其关联的强度又可以进一步划分为关联、聚合和合成,但说白了都是Has-A关系,合成聚合复用原则想表达的是优先考虑Has-A关系而不是Is-A关系复用代码,原因嘛可以自己从百度上找到一万个理由,需要说明的是,即使在Java的API中也有不少滥用继承的例子,例如Properties类继承了Hashtable类,Stack类继承了Vector类,这些继承明显就是错误的,更好的做法是在Properties类中放置一个Hashtable类型的成员并且将其键和值都设置为字符串来存储数据,而Stack类的设计也应该是在Stack类中放一个Vector对象来存储数据。记住:任何时候都不要继承工具类,工具是可以拥有并可以使用的,而不是拿来继承的。)

迪米特法则:迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。(迪米特法则简单的说就是如何做到"低耦合",门面模式和调停者模式就是对迪米特法则的践行。对于门面模式可以举一个简单的例子,你去一家公司洽谈业务,你不需要了解这个公司内部是如何运作的,你甚至可以对这个公司一无所知,去的时候只需要找到公司入口处的前台美女,告诉她们你要做什么,她们会找到合适的人跟你接洽,前台的美女就是公司这个系统的门面。再复杂的系统都可以为用户提供一个简单的门面,Java Web开发中作为前端控制器的Servlet或Filter不就是一个门面吗,浏览器对服务器的运作方式一无所知,但是通过前端控制器就能够根据你的请求得到相应的服务。调停者模式也可以举一个简单的例子来说明,例如一台计算机,CPU、内存、硬盘、显卡、声卡各种设备需要相互配合才能很好的工作,但是如果这些东西都直接连接到一起,计算机的布线将异常复杂,在这种情况下,主板作为一个调停者的身份出现,它将各个设备连接在一起而不需要每个设备之间直接交换数据,这样就减小了系统的耦合度和复杂度,如下图所示。迪米特法则用通俗的话来将就是不要和陌生人打交道,如果真的需要,找一个自己的朋友,让他替你和陌生人打交道。)

147.简述一下你了解的设计模式。

答:所谓设计模式,就是一套被反复使用的代码设计经验的总结(情境中一个问题经过证实的一个解决方案)。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式使人们可以更加简单方便的复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。
在GoF的《Design Patterns: Elements of Reusable Object-Oriented Software》中给出了三类(创建型[对类的实例化过程的抽象化]、结构型[描述如何将类或对象结合在一起形成更大的结构]、行为型[对在不同的对象之间划分责任和算法的抽象化])共23种设计模式,包括:Abstract Factory(抽象工厂模式),Builder(建造者模式),Factory Method(工厂方法模式),Prototype(原始模型模式),Singleton(单例模式);Facade(门面模式),Adapter(适配器模式),Bridge(桥梁模式),Composite(合成模式),Decorator(装饰模式),Flyweight(享元模式),Proxy(代理模式);Command(命令模式),Interpreter(解释器模式),Visitor(访问者模式),Iterator(迭代子模式),Mediator(调停者模式),Memento(备忘录模式),Observer(观察者模式),State(状态模式),Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibility(责任链模式)。
面试被问到关于设计模式的知识时,可以拣最常用的作答,例如:

工厂模式:工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。

代理模式:给一个对象提供一个代理对象,并由代理对象控制原对象的引用。实际开发中,按照使用目的的不同,代理可以分为:远程代理、虚拟代理、保护代理、Cache代理、防火墙代理、同步化代理、智能引用代理。

适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起使用的类能够一起工作。
模板方法模式:提供一个抽象类,将部分逻辑以具体方法或构造器的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法(多态实现),从而实现不同的业务逻辑。
除此之外,还可以讲讲上面提到的门面模式、桥梁模式、单例模式、装潢模式(Collections工具类和I/O系统中都使用装潢模式)等,反正基本原则就是拣自己最熟悉的、用得最多的作答,以免言多必失。

148.用Java写一个冒泡排序。

import java.util.Comparator;
 
/**
 * 排序器接口(策略模式: 将算法封装到具有共同接口的独立的类中使得它们可以相互替换)
 * @author nnngu
 *
 */
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);
}


import java.util.Comparator;
 
/**
 * 冒泡排序
 * 
 * @author nnngu
 *
 */
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程序员-张凯
来源:CSDN
原文:
https://blog.csdn.net/qq_41701956/article/details/88615277
https://blog.csdn.net/qq_41701956/article/details/88572728

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值