Java工程师面试题,整理自网络与博主各种笔试面试,持续更新

时间:2023-12-22 08:07:50

1、面向对象的特征有哪些方面?

封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。

多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。

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

作用域    当前类  同包 子类 其他

public        √        √       √      √

protected  √        √       √      ×

default       √       √       ×      ×

private       √        ×      ×      ×

类的成员不写访问修饰时默认为default。默认对于同一个包中的其他类相当于公开(public),对于不是同一个包中的其他类相当于私有(private)。受保护(protected)对子类相当于公开,对不是同一包中的没有父子关系的类相当于私有。

3、构造器(constructor)是否可被重写(override)?

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

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

答:不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同。

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

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

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

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

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

答:接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类,但前提是具体类必须有明确的构造函数。

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

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

9、数据类型之间的转换:

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

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

1)调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型; Integer.parseInt(a)   Integer.valueOf(a)

2)一种方法是将基本数据类型与空字符串(””)连接(+)即可获得其所对应的字符串;另一种方法是调用String 类中的valueOf(…)方法返回相应字符串 String.valueOf(int)   Integer.toString

10、如何实现字符串的反转及替换? 

答:这里博主写了几个常见的方式,代码如下所示:

 public class Reverse {
// 通过递归实现字符串反转
public String reverse1(String str) {
if (str.length() <= 1) {
return str;
} else {
return reverse1(str.substring(1)) + str.charAt(0);
}
}
// 通过一个新的字符串循环接收每个字符
public String reverse2(String str) {
String reStr = "";
for (int i = 0; i < str.length(); i++) {
reStr = str.charAt(i) + reStr;// 后面的加在前面
}
return reStr;
}
// 转换成数组来循环接收每个元素
public String reverse3(String str) {
char[] charArr = str.toCharArray();
String reStr = "";
for (int i = 0; i < charArr.length; i++) {
reStr = charArr[i] + reStr;
}
return reStr;
}
// 转换成StringBuffer来调用他的反转方法
public String reverse4(String str) {
return new StringBuffer(str).reverse().toString();
}
public static void main(String[] args) {
Reverse re = new Reverse();
String str = "ABCDE";
System.out.println(re.reverse4(str));
}
}

11、列出一些你常见的运行时异常? 

答:

ArithmeticException(算术异常)

ClassCastException (类转换异常)

IllegalArgumentException (非法参数异常)

IndexOutOfBoundsException (下标越界异常)

NullPointerException (空指针异常)

SecurityException (安全异常)

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

13、什么是进程,什么是线程?为什么需要多线程编程?

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是操作系统进行资源分配和调度的一个独立单位;

线程是进程的一个实体,是CPU调度和分 派的基本单位,是比进程更小的能独立运行的基本单位。

线程的划分尺度小于进程,这使得多线程程序的并发性高;进程在执行时通常拥有独立的内存单元,而线程之间可以共享内存。使用多线程的编程通常能够带来更好的性能和用户体验,但是多线程的程序对于其他程序是不友好的,因为它占用了更多的CPU资源。

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

1. 加载驱动。

  1. Class.forName("com.mysql.jdbc.Driver");

2. 创建连接。

  1. Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/xxx");  //xxx:数据库的名称

3. 创建语句。

  1. PreparedStatement pstmt = con.prepareStatement("select * from t_user where id=?");
  2. pstmt.setInt(1, 1);

4. 执行语句。

  1. ResultSet rs = pstmt.executeQuery();

5. 处理结果。

  1. while(rs.next()) {
  2. System.out.println(rs.getInt(1) + " - " + rs.getString(2));    }

6. 关闭资源。

  1. finally {
  2. if(con != null) {
  3. try {
  4. con.close();
  5. } catch (SQLException e) {                e.printStackTrace();
  6. }
  7. }
  8. }

整体代码:

 public class JDBCDemo {
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String URL = "jdbc:mysql://localhost:3306/db_jsp";
private static final String USER = "root";
private static final String PASSWORD = "123456"; public static void main(String[] args) {
PreparedStatement pstmt = null;
Connection con = null;
try {
Class.forName(DRIVER);
System.out.println("加载驱动成功");
con = DriverManager.getConnection(URL, USER, PASSWORD);
System.out.println("获取连接成功");
pstmt = con
.prepareStatement("select * from t_user where id=?");
pstmt.setInt(1, 1);
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getInt(1)+"\t"+rs.getString(2)+"\t"+rs.getString(3));
}
} catch (Exception e) {
System.out.println("加载驱动失败");
e.printStackTrace();
}finally{
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
if (con != null) {
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
} }

15.Statement和PreparedStatement有什么区别?哪个性能更好? 
与Statement相比

①PreparedStatement接口代表预编译的语句,它主要的优势在于可以减少SQL的编译错误并增加SQL的安全性(减少SQL注射攻击的可能性)

②PreparedStatement中的SQL语句是可以带参数的,避免了用字符串连接拼接SQL语句的麻烦和不安全;

③当批量处理SQL或频繁执行相同的查询时,PreparedStatement有明显的性能上的优势,由于数据库可以将编译优化后的SQL语句缓存起来,下次执行相同结构的语句时就会很快(不用再次编译和生成执行计划)。

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

17、Java中是如何支持正则表达式操作的? 
答:Java中的String类提供了支持正则表达式操作的方法,包括:matches()、replaceAll()、replaceFirst()、split()。此外,Java中可以用Pattern类表示正则表达式对象,它提供了丰富的API进行各种正则表达式操作,请参考下面面试题的代码。

面试题: - 如果要从字符串中截取第一个英文左括号之前的字符串,例如:北京市(朝阳区)(西城区)(海淀区),截取结果为:北京市,那么正则表达式怎么写?

  1. import java.util.regex.Matcher;
  2. import java.util.regex.Pattern;
  3. class RegExpTest {
  4. public static void main(String[] args){
  5. String str = "北京市(朝阳区)(西城区)(海淀区)";
  6. Pattern p = Pattern.compile(".*?(?=\\()");
  7. Matcher m = p.matcher(str);
  8. if(m.find()) {
  9. System.out.println(m.group());        }
  10. }
  11. }

18、获得一个类的类对象有哪些方式? 
答: 
- 方法1:类型.class,例如:String.class 
- 方法2:对象.getClass(),例如:"hello".getClass() 
- 方法3:Class.forName(),例如:Class.forName("java.lang.String")

19、如何通过反射创建对象? 
答: 
- 方法1:通过类对象调用newInstance()方法,例如:String.class.newInstance() 
- 方法2:通过类对象的getConstructor()或getDeclaredConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象,例如:String.class.getConstructor(String.class).newInstance("Hello");

20、如何通过反射调用对象的方法? 
答:请看下面的代码:

  1. import java.lang.reflect.Method;
  2. class MethodInvokeTest {
  3. public static void main(String[] args) throws Exception {
  4. String str = "hello";
  5. Method m = str.getClass().getMethod("toUpperCase");
  6. System.out.println(m.invoke(str));
  7. // HELLO
  8. }
  9. }

21、简述一下面向对象的"六原则一法则"。 
答: 
1)单一职责原则:一个类只做它该做的事情。(单一职责原则想表达的就是"高内聚",写代码最终极的原则只有六个字"高内聚、低耦合")
2)开闭原则:软件实体应当对扩展开放,对修改关闭。(在理想的状态下,当我们需要为一个软件系统增加新功能时,只需要从原来的系统派生出一些新类就可以,不需要修改原来的任何一行代码。要做到开闭有两个要点:①抽象是关键,一个系统中如果没有抽象类或接口系统就没有扩展点;②封装可变性,将系统中的各种可变因素封装到一个继承结构中,如果多个可变因素混杂在一起,系统将变得复杂而换乱) 
3)依赖倒转原则:面向接口编程。(该原则说得直白和具体一些就是声明方法的参数类型、方法的返回类型、变量的引用类型时,尽可能使用抽象类型而不用具体类型,因为抽象类型可以被它的任何一个子类型所替代) 
4)里氏替换原则:任何时候都可以用子类型替换掉父类型。(子类一定是增加父类的能力而不是减少父类的能力,因为子类比父类的能力更多,把能力多的对象当成能力少的对象来用当然没有任何问题。) 
5)接口隔离原则:接口要小而专,绝不能大而全。(臃肿的接口是对接口的污染,既然接口表示能力,那么一个接口只应该描述一种能力,接口也应该是高度内聚的。Java中的接口代表能力、代表约定、代表角色,能否正确的使用接口一定是编程水平高低的重要标识。) 
6)合成聚合复用原则:优先使用聚合或合成关系复用代码。(通过继承来复用代码是面向对象程序设计中被滥用得最多的东西,记住:任何时候都不要继承工具类,工具是可以拥有并可以使用的,而不是拿来继承的。) 
迪米特法则:迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。(迪米特法则简单的说就是如何做到"低耦合",门面模式和调停者模式就是对迪米特法则的践行。Java Web开发中作为前端控制器的Servlet或Filter不就是一个门面吗,浏览器对服务器的运作方式一无所知,但是通过前端控制器就能够根据你的请求得到相应的服务。调停者模式也可以举一个简单的例子来说明,例如一台计算机,CPU、内存、硬盘、显卡、声卡各种设备需要相互配合才能很好的工作。迪米特法则用通俗的话来将就是不要和陌生人打交道,如果真的需要,找一个自己的朋友,让他替你和陌生人打交道。)

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

-工厂模式:工厂类可以根据条件生成不同的子类实例,这些子类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作(多态方法)。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。 
- 代理模式:给一个对象提供一个代理对象,并由代理对象控制原对象的引用。实际开发中,按照使用目的的不同,代理可以分为:远程代理、虚拟代理、保护代理、Cache代理、防火墙代理、同步化代理、智能引用代理。 
- 适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起使用的类能够一起工作。 
- 模板方法模式:提供一个抽象类,将部分逻辑以具体方法或构造器的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法(多态实现),从而实现不同的业务逻辑。

23、用Java写一个单例类。 

饿汉式单例

  1. public class Singleton {
  2. private Singleton(){}
  3. private static Singleton instance = new Singleton();
  4. public static Singleton getInstance(){        return instance;
  5. }
  6. }

懒汉式单例

  1. public class Singleton {
  2. private Singleton() {}
  3. private static Singleton instance = null;
  4. public static synchronized Singleton getInstance(){
  5. if (instance == null)
  6. instance = new Singleton();
  7. return instance;
  8. }
  9. }

注意:实现一个单例有两点注意事项,①将构造器私有,不允许外界通过构造器创建对象;②通过公开的静态方法向外界返回类的唯一实例。这里有一个问题可以思考:spring的IoC容器可以为普通的类创建单例,它是怎么做到的呢?

24.什么是DAO模式?

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

25.Servlet的生命周期

Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的service方法,service方法会调用与请求对应的doGet或doPost等方法;当服务器关闭会项目被卸载时服务器会将Servlet实例销毁,此时会调用Servlet的destroy方法。

26.转发(forward)和重定向(redirect)的区别?

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

2)redirect就是服务器端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,因此从浏览器的地址栏中可以看到跳转后的链接地址。

3)前者更加高效,在前者可以满足需要时,尽量使用转发(通过RequestDispatcher对象的forward方法,RequestDispatcher对象可以通过ServletRequest对象的getRequestDispatcher方法获得),并且,这样也有助于隐藏实际的链接;在有些情况下,比如,需要跳转到一个其它服务器上的资源,则必须使用重定向(通过HttpServletResponse对象调用其sendRedirect方法)。

27.get和post请求的区别?

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

②get将表单中数据按照name=value的形式,添加到action 所指向的URL 后面,并且两者使用“?”连接,而各个变量之间使用“&”连接;post是将表单中的数据放在HTML头部(header),传递到action所指向URL;

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

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

28、JSP 和Servlet 有有什么关系?

答:其实这个问题在上面已经阐述过了,Servlet是一个特殊的Java程序,它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。

JSP本质上是Servlet的一种简易形式, JSP会被服务器处理成一个类似于Servlet的Java程序,可以简化页面内容的生成。

Servlet和JSP最主要的不同点在于,Servlet 的应用逻辑是在Java 文件中,并且完全从表示层中的HTML分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp 的文件(有人说,Servlet就是在Java中写HTML,而JSP就是在HTML中写Java代码,当然,这个说法还是很片面的)。

JSP侧重于视图,Servlet更侧重于控制逻辑,在MVC架构模式中,JSP适合充当视图(view)而Servlet适合充当控制器(controller)。

29、JSP中的四种作用域?

答:page、request、session和application,具体如下:

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

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

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

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

30.实现会话跟踪的技术有哪些?

答:由于HTTP协议本身是无状态的,服务器为了区分不同的用户,就需要对用户会话进行跟踪,简单的说就是为用户进行登记,为用户分配唯一的ID,下一次用户在请求中包含此ID,服务器据此判断到底是哪一个用户。

①URL 重写:在URL中添加用户会话的信息作为请求的参数,或者将唯一的会话ID添加到URL结尾以标识一个会话。

②设置表单隐藏域:将和会话跟踪相关的字段添加到隐式表单域中,这些信息不会在浏览器中显示但是提交表单时会提交给服务器。

③cookie:cookie当用户通过浏览器和服务器建立一次会话后,会话ID就会随响应信息返回存储在基于窗口的cookie中,那就意味着只要浏览器没有关闭,会话没有超时,下一次请求时这个会话ID又会提交给服务器让服务器识别用户身份。会话中可以为用户保存信息。会话对象是在服务器内存中的,而基于窗口的cookie是在客户端内存中的。

④HttpSession:在所有会话跟踪技术中,HttpSession对象是最强大也是功能最多的。当一个用户第一次访问某个网站时会自动创建HttpSession,每个用户可以访问他自己的HttpSession。与上面三种方式不同的是,HttpSession放在服务器的内存中

31.JSP中的静态包含和动态包含有什么区别? 
答:静态包含是通过JSP的include指令包含页面,动态包含是通过JSP标准动作<jsp:forward>包含页面。静态包含是编译时包含,如果包含的页面不存在则会产生编译错误,而且两个页面的"contentType"属性应保持一致,因为两个页面会合二为一,只产生一个class文件,因此被包含页面发生的变动再包含它的页面更新前不会得到更新。动态包含是运行时包含,可以向被包含的页面传递参数,包含页面和被包含页面是独立的,会编译出两个class文件,如果被包含的页面不存在,不会产生编译错误,也不影响页面其他部分的执行。代码如下所示:

<%-- 静态包含 --%><%@ include file="..." %> <%-- 动态包含 --%><jsp:include page="...">    <jsp:param name="..." value="..." /></jsp:include>

32、什么是Web Service(Web服务)? 
答:从表面上看,Web Service就是一个应用程序,它向外界暴露出一个能够通过Web进行调用的API。例如可以创建一个提供天气预报的Web Service,那么无论你用哪种编程语言开发的应用都可以通过调用它的API并传入城市信息来获得该城市的天气预报。

补充:这里必须要提及的一个概念是SOA(Service-Oriented Architecture,面向服务的架构)显然,Web Service是SOA的一种较好的解决方案,它更多的是一种标准,而不是一种具体的技术。

33、hashmap和hashtable区别

1.hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
   2.hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。
   3.hashMap允许空键值,而hashTable不允许。

34、Socket的通信机制?

套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 
TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。
套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。

客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

35、Http的通信机制?
HTTP协议即超文本传送协议(Hypertext Transfer Protocol 
),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。

HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。从建立连接到关闭连接的过程称为“一次连接”。

1)在HTTP 1.0中,客户端的每次请求都要求建立一次单独的连接,在处理完本次请求后,就自动释放连接。

2)在HTTP 
1.1中则可以在一次连接中处理多个请求,并且多个请求可以重叠进行,不需要等待一个请求结束后再发送下一个请求。

由于HTTP在每次请求结束后都会主动释放连接,因此HTTP连接是一种“短连接”,要保持客户端程序的在线状态,需要不断地向服务器发起连接请求。通常的做法是即时不需要获得任何数据,客户端也保持每隔一段固定的时间向服务器发送一次“保持连接”的请求,服务器在收到该请求后对客户端进行回复,表明知道客户端“在线”。若服务器长时间无法收到客户端的请求,则认为客户端“下线”,若客户端长时间无法收到服务器的回复,则认为网络已经断开。
由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 
Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。

而HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。

很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。

36、HttpServlet容器响应Web客户请求流程?

1)Web客户向Servlet容器发出Http请求;

2)Servlet容器解析Web客户的Http请求;

3)Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息;

4)Servlet容器创建一个HttpResponse对象;

5)Servlet容器调用HttpServlet的service方法,这个方法中会根据request的Method来判断具体是执行doGet还是doPost,把HttpRequest和HttpResponse对象作为service方法的参数传给HttpServlet对象;

6)HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息;

7)HttpServlet调用HttpResponse的有关方法,生成响应数据;

8)Servlet容器把HttpServlet的响应结果传给Web客户

37、hibernate中Session的load和get方法的区别是什么? 
答:主要有以下三项区别: 
① 如果没有找到符合条件的记录,get方法返回null,load方法抛出异常。 
② get方法直接返回实体类对象,load方法返回实体类对象的代理。 
③ 在Hibernate 3之前,get方法只在一级缓存中进行数据查找,如果没有找到对应的数据则越过二级缓存,直接发出SQL语句完成数据读取;load方法则可以从二级缓存中获取数据;从Hibernate 3开始,get方法不再是对二级缓存只写不读,它也是可以访问二级缓存的。

说明:对于load()方法Hibernate认为该数据在数据库中一定存在可以放心的使用代理来实现延迟加载,如果没有数据就抛出异常,而通过get()方法获取的数据可以不存在。

38、如何理解Hibernate的延迟加载机制

答:延迟加载就是并不是在读取的时候就把数据加载进来,而是等到使用时再加载。Hibernate使用了虚拟代理机制实现延迟加载。返回给用户的并不是实体本身,而是实体对象的代理。代理对象在用户调用getter方法时就会去数据库加载数据。

39、简述Hibernate常见优化策略。

①制定合理的缓存策略

② 采用合理的Session管理机制

③ 尽量使用延迟加载特性

④如果可以, 选用基于version的乐观锁替代悲观锁

⑤在开发过程中, 开启hibernate.show_sql选项查看生成的SQL, 从而了解底层的状况;开发完成后关闭此选项

40、什么是IoC和DI?DI是如何实现的? 
答:IoC叫控制反转,是Inversion of Control的缩写,控制反转是把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的"控制反转"就是对组件对象控制权的转移,从程序代码本身转移到了外部容器,由容器来创建对象并管理对象之间的依赖关系。

控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象,是容器在对象初始化时不等对象请求就主动将依赖传递给它。通过IOC反转控制DI依赖注入完成各个层之间的注入,使得层与层之间实现完全脱耦,增加运行效率利于维护。

41、解释一下什么叫AOP(面向切面编程)? 
答:
    spring的AOP面向切面编程,实现在不改变代码的情况下完成对方法的增强。比较常用的就是spring的声明式事务管理,底层通过AOP实现,避免了我们每次都要手动开启事物,提交事务的重复性代码,使得开发逻辑更加清晰。

简单点解释,比方说你想在你的service层所有类中都加上一个打印‘你好’的功能这你经可以用aop思想来做,你先写个类写个方法,方法经实现打印‘你好’然后你Ioc这个类 ref=“service.*”让每个类都注入。

aop就是面向切面的编程。比如说你每做一次对数据库操作,都要生成一句日志。如果,你对数据库的操作有很多类,那你每一类中都要写关于日志的方法。但是如果你用aop,那么你可以写一个方法,在这个方法中有关于数据库操作的方法,每一次调用这个方法的时候,就加上生成日志的操作。

42、选择使用Spring框架的原因(Spring框架为企业级开发带来的好处)?

答:可以从以下几个方面作答:

1. IoC容器:IoC容器帮助应用程序管理对象以及对象之间的依赖关系,对象之间的依赖关系如果发生了改变只需要修改配置文件而不是修改代码,因为代码的修改可能意味着项目的重新构建和完整的回归测试。有了IoC容器,程序员再也不需要自己编写工厂、单例,这一点特别符合Spring的精神“不要重复的发明*”。

2. AOP:面向切面编程,将所有的横切关注功能封装到切面(aspect)中,通过配置的方式将横切关注功能动态添加到目标代码上,进一步实现了业务逻辑和系统服务之间的分离。另一方面,有了AOP程序员可以省去很多自己写代理类的工作。

3. MVC:Spring的MVC框架是非常优秀的,从各个方面都可以甩Struts 2几条街,为Web表示层提供了更好的解决方案。

4. 事务管理:Spring以宽广的胸怀接纳多种持久层技术,并且为其提供了声明式的事务管理,在不需要任何一行代码的情况下就能够完成事务管理。

43、 简述拦截器的工作原理以及你在项目中使用过哪些自定义拦截器

答:Struts 2中定义了拦截器的接口以及默认实现,实现了Interceptor接口或继承了AbstractInterceptor的类可以作为拦截器。接口中的init()方法在拦截器被创建后立即被调用,它在拦截器的生命周期内只被调用一次,可以在该方法中对相关资源进行必要的初始化。每拦截一个请求,intercept()方法就会被调用一次。destory()方法将在拦截器被销毁之前被调用, 它在拦截器的生命周期内也只被调用一次。

项目中使用过的有权限拦截器、执行时间拦截器、令牌拦截器等。

44、谈一下拦截器和过滤器的区别

答:拦截器和过滤器都可以用来实现横切关注功能,其区别主要在于:

1、拦截器是基于java反射机制的,而过滤器是基于函数回调的。
2、过滤器依赖于servlet容器,而拦截器不依赖于servlet容器。
3、拦截器只能对Action请求起作用,而过滤器则可以对几乎所有请求起作用。
4、拦截器可以访问Action上下文、值栈里的对象,而过滤器不能。
5、在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次。

过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者struts的action前统一设置字符集,或者去除掉一些非法字符.

拦截器,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,在你调用方法前打印出字符串(或者做其它业务逻辑的操作),也可以在你调用方法后打印出字符串,甚至在你抛出异常的时候做业务逻辑的操作。

执行顺序:过滤前 - 拦截前 - Action处理 - 拦截后 - 过滤后。

个人认为过滤是一个横向的过程,首先把客户端提交的内容进行过滤(例如未登录用户不能访问内部页面的处理);过滤通过后,拦截器将检查用户提交数据的验证,做一些前期的数据处理,接着把处理后的数据发给对应的Action;Action处理完成返回后,拦截器还可以做其他过程(还没想到要做啥),再向上返回到过滤器的后续操作。

45、struts1.2和struts2.0的区别?

struts1.2和struts2.0的对比

a、Action类:

struts1.2要求Action类继承一个基类。struts2.0 Action要求继承ActionSupport基类

b、线程模式

struts1.2 Action是单例模式的并且必须是线程安全的,因为仅有一个Action的实例来处理所有的请求。 struts2.0 Action为每一个请求产生一个实例,因此没有线程安全问题。

c、Servlet依赖

struts1.2 Action依赖于Servlet API,因为当一个Action被调用时HttpServletRequest和HttpServletResponse被传递给execut方法。 struts2.0 Action不依赖于容器,允许Action脱离容器单独测试。

46、常见的网络协议有哪些?

1.IP协议:互联网协议

主要用于负责IP寻址、路由选择和IP数据包的分割和组装。通常我们所说的IP地址可以理解为符合IP协议的地址。

2.TCP协议:传输控制协议

该协议主要用于在主机间建立一个虚拟连接,以实现高可靠性的数据包交换。IP协议可以进行IP数据包的分割和组装,但是通过IP协议并不能清楚地了解到数据包是否顺利地发送给目标计算机。而使用TCP协议就不同了,在该协议传输模式中在将数据包成功发送给目标计算机后,TCP会要求发送一个确认;如果在某个时限内没有收到确认,那么TCP将重新发送数据包。另外,在传输的过程中,如果接收到无序、丢失以及被破坏的数据包,TCP还可以负责恢复。

3.FTP(File Transfer Protocol):远程文件传输协议,允许用户将远程主机上的文件拷贝到自己的计算机上。

4.HTTP:超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。

5.ARP协议:AddressResolutionProtocol地址解析协议

简单地说,ARP协议主要负责将局域网中的32为IP地址转换为对应的48位物理地址,即网卡的MAC地址。

47、计算机网络分层,每层所用协议,协议所占端口

(1)应用层:与其他计算机进行通讯的一个应用,它是对应应用程序的通信服务的。示例:telnet,HTTP,FTP,WWW,NFS,SMTP等。 
    (2)表示层:这一层的主要功能是定义数据格式及加密。示例:加密,ASII等。 
    (3)会话层:他定义了如何开始、控制和结束一个会话,包括对多个双向小时的控制和管理,以便在只完成连续消息的一部分时可以通知应用,从而使表示层看到的数据是连续的。示例:RPC,SQL等。 
   (4)传输层:这层的功能包括是否选择差错恢复协议还是无差错恢复协议,及在同一主机上对不同应用的数据流的输入进行复用,还包括对收到的顺序不对的数据包的重新排序功能。示例:TCP,UDP,SPX。 
   (5)网络层:这层对端到端的包传输进行定义,他定义了能够标识所有结点的逻辑地址,还定义了路由实现的方式和学习的方式。。示例:IP,IPX等。 
   (6)数据链路层:他定义了在单个链路上如何传输数据。

(7)物理层:OSI的物理层规范是有关传输介质的特性标准,这些规范通常也参考了其他组织制定的标准。

48、html访问全过程

A)解析Web页面的URL,得到Web服务器的域名
    B)通过DNS服务器获得Web服务器的IP地址

I)与Web服务器建立TCP连接
    E)与Web服务器建立HTTP连接

C)从Web服务器获得URL指定的文档
    G)浏览器解释页面文档,并显示在屏幕

49、classloader原理

1.classLoader的介绍及加载过程

与普通程序不同的是,Java程序(class文件)并不是本地的可执行程序。当运行Java程序时,首先运行JVM(Java虚拟机),然后再把Java class加载到JVM里头运行,负责加载Java class的这部分就叫做Class Loader。所以classLoader的目的在于把class文件装入到jvm中。

那么classLoader又在那里的啦?又由谁调用呢?其实classLoader只是jvm的一个实现的一部分。Jvm提供的一个*的classLoader(bootStrap classLoader),bootStrap classLoader负责加载java核心的API以满足java程序最基本的需求。Jvm还提供的两个classLoader,其中Extension ClassLoader负责加载扩展的Java class,Application ClassLoader负责加载应用程序自身的类。而Extension ClassLoader和Application ClassLoader则由bootStrap classLoader加载。

2.classLoader加载的基本流程

当运行一个程序的时候,JVM启动,运行bootstrap classloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程。

3.classLoader加载的方式

其实classLoader在加载class文件的时候就采用的双亲委托模式。每一个自定义ClassLoader都必须继承ClassLoader这个抽象类,而每个ClassLoader都会有一个parent ClassLoader,我们可以看一下ClassLoader这个抽象类中有一个getParent()方法,这个方法用来返回当前ClassLoader的parent。

50、快速排序原理

原理:

快速排序也是分治法思想的一种实现,他的思路是使数组中的每个元素与基准值(Pivot,通常是数组的首个值,A[0])比较,数组中比基准值小的放在基准值的左边,形成左部;大的放在右边,形成右部;接下来将左部和右部分别递归地执行上面的过程:选基准值,小的放在左边,大的放在右边。。。直到排序结束。

步骤:

1.找基准值,设Pivot = a[0]

2.分区(Partition):比基准值小的放左边,大的放右边,基准值(Pivot)放左部与右部的之间。

3.进行左部(a[0] - a[pivot-1])的递归,以及右部(a[pivot+1] - a[n-1])的递归,重复上述步骤。

  1. 1.//快速排序
  2. 2.void quick_sort(int s[], int l, int r)
  3. 3.{
  4. 4.    if (l < r)
  5. 5.    {
  6. 6.        //Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
  7. 7.       int i = l, j = r, x = s[l];
  8. 8.       while (i < j)
  9. 9.       {
  10. 10.        while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
  11. 11.                j--;
  12. 12.          if(i < j)
  13. 13.          s[i++] = s[j];
  14. 14.
  15. 15.       while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
  16. 16.            i++;
  17. 17.         if(i < j)
  18. 18.          s[j--] = s[i];
  19. 19.        }
  20. 20.        s[i] = x;
  21. 21.        quick_sort(s, l, i - 1); // 递归调用
  22. 22.        quick_sort(s, i + 1, r);
  23. 23.    }
  24. 24.}

51、各种集合类之间的区别

1.ArrayList: 元素单个,效率高,多用于查询

2.Vector:  元素单个,线程安全,多用于查询

3.LinkedList:元素单个,多用于插入和删除

4.HashMap:  元素成对,元素可为空

5.HashTable: 元素成对,线程安全,元素不可为空

52、内存溢出和内存泄漏

内存溢出是指已有的数据超过了其获得到的内存所能存储的范围,比如用一个字节存放1000这个数字就属于内存溢出。比如说你申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。

Java内存泄漏就是没有及时清理内存垃圾,导致系统无法再给你提供内存资源(内存资源耗尽)。Java内存泄露是说程序逻辑问题,造成申请的内存无法释放.这样的话无论多少内存,早晚都会被占用光的.最简单的例子就是死循环了.由于程序判断错误导经常发生此事。

53、jvm布局

以下是JVM的一个基本架构图,在这个基本架构图中,栈有两部份,Java线程栈以及本地方法栈

Java工程师面试题,整理自网络与博主各种笔试面试,持续更新

在JVM中堆空间划分如下图所示

Java工程师面试题,整理自网络与博主各种笔试面试,持续更新

上图中,刻画了Java程序运行时的堆空间,可以简述成如下2条

1.JVM中堆空间可以分成三个大区,新生代、老年代、永久代

2.新生代可以划分为三个区,Eden区,两个幸存区

Jvm主要包括下面两面方面:

· Java代码编译和执行的整个过程

· JVM内存管理及垃圾回收机制

54、在浏览器中输入www.baidu.com后执行的全部过程

1、客户端浏览器通过DNS解析到www.baidu.com的IP地址220.181.27.48,通过这个IP地址找到客户端到服务器的路径。客户端浏览器发起一个HTTP会话到220.161.27.48,然后通过TCP进行封装数据包,输入到网络层。

2、在客户端的传输层,把HTTP会话请求分成报文段,添加源和目的端口,如服务器使用80端口监听客户端的请求,客户端由系统随机选择一个端口如5000,与服务器进行交换,服务器把相应的请求返回给客户端的5000端口。然后使用IP层的IP地址查找目的端。

3、客户端的网络层不用关系应用层或者传输层的东西,主要做的是通过查找路由表确定如何到达服务器,期间可能经过多个路由器,这些都是由路由器来完成的工作,我不作过多的描述,无非就是通过查找路由表决定通过那个路径到达服务器。

4、客户端的链路层,包通过链路层发送到路由器,通过邻居协议查找给定IP地址的MAC地址,然后发送ARP请求查找目的地址,如果得到回应后就可以使用ARP的请求应答交换的IP数据包现在就可以传输了,然后发送IP数据包到达服务器的地址。

55、IO流类

Java工程师面试题,整理自网络与博主各种笔试面试,持续更新