二阶段面试题

二阶段面试题

1、简述文件过滤器的accept的重写规则

该方法要求传入一个File类型的参数,过滤器accept方法的重写规则就是当该file符合过滤器要求时方法应当返回为true否则返回false。

2、当传入一个字符串作为路径实例化File,此时如果调用该File对象的length方法返回值为0可能的情况有哪些?

  • 路径所表示的是一个目录
  • 路径失效,可能与实际文件的路径存在拼写错误
  • 实际文件位置与路径描述不一致

3、简述IO的分类

  • 按照方向分为输入与输出,输入负责读取数据,输出负责写出数据
  • 按照读写单位分为字节流与字符流。字节流的超类为InputStream和OutputStream,字节流的超类为Reader和Writer
  • 流还分为节点流与处理流

4、节点流与处理流的区别

  • 节点流是实际连接程序与另一端的管道,负责实际读写数据的流。
  • 处理流不能独立存在,必须连接在其他流上,当数据经过当前流时对数据进行加工,简化我们的读写操作

5、字节流输出流的write(int d)和write(byte[] data)功能

  • write(int d)是写出1个字节,写出的是给定的int值2进制的低八位
  • write(byte[] data)是块写操作,将给定的字节数组所有内容一次性写出

6、缓冲字节流的原理

缓冲流内部默认维护一个8kb的字节数组

以块读写形式保证读写效率

7、流连接的意义

在一个低级流上串联一组高级流,可以在读写的过程中以流水线式的在各个高级流上对数据进行加工,简化我们的读写操作。

8、简述客户端与服务端建立TCP连接的过程

  • 服务端实例化ServerSocket并打开服务端口
  • 服务端调用ServerSocket的accept方法等待客户端连接
  • 客户端实例化Socket指定服务端 的IP和端口与服务端建立连接

9、什么是并发

并发是指多个线程在微观的角度是走走停停的,宏观的感觉是"同时"执行的现象。

10、创建线程的两种方式是什么

  • 继承Thread并重写run方法。
  • 实现Runnable接口并重写run方法单独定义线程任务。然后在实例化Thread的同时将任务传入。

11、线程的run方法和start方法的作用

  • run方法是线程要执行的任务
  • start方法是用来启动线程

12、如何保证同步安全并提高并发效率

使用同步块来有效的缩小同步范围可以在保证并发安全的前提下尽可能提高并发效率

13、同步监视器对象的选取原则

  • 同步监视器对象必须要保证多个线程看到的是同一个对象
  • 同步监视器对象首选为多个线程并发操作的临界资源
  • 静态方法上通常使用当前类的类对象(4分)

14、如何实现代码间的互斥

使用多个synchronized锁定多个代码片段,并且指定的同步监视器对象相同时,这些代码间就是互斥的

15、静态方法上使用synchronized后,锁对象是谁?

静态方法上使用synchronized后同步监视器对象为当前类的类对象

16、类名.class.getResource(“.”)和类名.class.getClassLoader().getResource(“.”)分别表示的位置是哪里?

  • 类名.class.getResource(“.”)表示的位置是当前类字节码文件所在的目录
  • 类名.class.getClassLoader().getResource(“.”)表示的位置是类加载路径,可以理解是当前类所在的最外层包的上一级。比如当前类包名:package com.webserver.core那么这里表示的就是com包的上一级。

17、类对象Class中getMethods()和getDeclaredMethods()的功能和区别?

  • getMethods()可以获取当前类中所有的公开方法,包含从超类继承的方法。

  • getDeclaredMethods()可以获取当前类自己定义的所有方法,包含私有方法等,但是不包含从超类继承的方法。

18、注解@Target的作用是什么?

@Target注解的作用是标注当前注解可是被应用的位置。对应的是ElementType中各个枚举值。

19、注解@Retention的作用是什么?

@Retention注解的作用是标注当前注解的保留级别,保留级别只有三个

  • RetentionPolicy.SOURCE:当前注解仅保留在源码中
  • RetentionPolicy.CLASS:当前注解保留在编译后的字节码文件中,但是不可被反射机制调用
  • RetentionPolicy.RUNTIME:当前注解保留在编译后的字节码文件中,可被反射机制调用

20、简述反射机制调用私有方法的过程?

  1. 加载类对象
  2. 通过类对象的getDeclaredMethod()方法获取私有方法
  3. 通过Method对象调用setAccessible(true)打开访问权限
  4. 通过Method对象调用invoke()方法执行该方法
  5. 执行后应当调用setAccessible(false)将权限关闭

21、Map的三种遍历方式?

遍历所有的key,对应的方法为:public Set keySet()

遍历所有的键值对,对应的方法为:public Set entrySet()或者使用基于lambda表达式的forEach方法

遍历所有的value,对应的方法为:public Collection values()

22、编程题

编程题要求(每题30分):

​ 编程题至少考察一个(上面基础题好的可以考代码量多的编程题)

​ 代码运行不报错(无论是否实现功能,给5分)

​ 功能正确实现(25)

编写程序完成文件复制

需求:将项目目录下的test.dat文件复制为test_cp.dat

答案(主要逻辑部分):

try(
	FileInputStream fis = new FileInputStream("test.dat");
	FileOutputStream fis = new FileOutputStream("test.dat");
){
	byte[] buf = new byte[1024];
	int len;
	while((len = fis.read(buf))!=-1){
		fos.write(buf,0,len);	
	}
}catch(IOException e){...}

编写程序完成对象序列化

需求:将一个User对象序列化到文件user.obj中。User对象属性四个即可:String username,String password,String nickname,int age

答案:

审查定义的User是否实现了序列化接口以及构造方法,get,set方法。

代码(主要逻辑部分):

User user = new User();//这里用全参数构造器在这里一次性初始化
//也可以在这里调用属性的set方法逐个初始化(上述两种创建形式都可以)
try(
	ObjectOutputStream oos = new ObjectOutputStream(
		new FileOutputStream("user.obj")
	);
){
	oos.writeObject(user);
}catch(IOException e){...}

编写程序完成客户端向服务端发送一行字符串

需求:客户端连接服务端发送一行"helloworld"并在服务端读取后输出

答案:

客户端代码

public class Client {
    
    
    private Socket socket;
    public Client(){
    
    
        try {
    
    
            socket = new Socket("localhost",8088);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
    public void start(){
    
    
        try {
    
             
            OutputStream out = socket.getOutputStream();
            OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);//这里检查是否指定了字符集
            BufferedWriter bw = new BufferedWriter(osw);
            PrintWriter pw = new PrintWriter(bw,true);//这里检查有没有自动行刷新
            pw.println("helloworld");//这里检查是否调用的是println方法。
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } finally {
    
    
            try {
    
    
                socket.close();
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
    
    
        Client client = new Client();
        client.start();
    }

服务端代码

package socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
 * 聊天室服务端
 */
public class Server {
    
    
    private ServerSocket serverSocket;
    public Server(){
    
    
        try {
    
    
            serverSocket = new ServerSocket(8088);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
    public void start(){
    
    
        try {
    
       
            Socket socket = serverSocket.accept();
            InputStream in = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(in, StandardCharsets.UTF_8);//检查是否指定了字符集
            BufferedReader br = new BufferedReader(isr);   
            String message = br.readLine();
            System.out.println("客户端说:"+message);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
    
    
        Server server = new Server();
        server.start();
    }
}


  1. 请描述HTTP请求的结构

    • 请求由三部分构成:请求行,消息头,消息正文
    • 请求行为一行字符串,格式:请求方式抽象路径协议版本
    • 消息头为若干行字符串,格式:消息头名字<:SP>消息头的值。所有消息头部分完毕后有一个单独的
    • 消息正文为2进制内容
  2. 请描述HTTP响应的结构

    • 响应由三部分构成:状态行,响应头,响应正文
    • 状态行为一行字符串,格式:协议版本状态代码状态描述
    • 响应头为若干行字符串,格式:响应头名字<:SP>响应头的值。所有响应头部分完毕后有一个单独的
    • 响应正文为2进制内容
  3. HTTP协议规定客户端与服务端的一次交互步骤是什么

    • 浏览器与服务端建立TCP连接
    • 浏览器发送HTTP的请求内容
    • 服务端接收请求后对请求进行处理并予以发送HTTP的响应内容
    • 服务端与客户端断开TCP连接
  4. 请描述状态代码的分类和常见的状态代码

    • 状态代码被分为5类,分别是:1xx,2xx,3xx,4xx,5xx
    • 1xx为保留部分,2xx为成功,3xx为重定向,4xx为处理错误,但是由客户端导致,5xx为处理错误,是由服务端导致
    • 200:处理成功,并予以响应。302:重定向到Location头指定的位置。404:资源未找到。500:服务端内部错误
  5. 常用的响应头和作用

    • Content-Type:说明响应正文的数据类型,对应MIME的值
    • Content-Length:说明响应正文的数据长度,单位是字节
    • Location:说明重定向到指定的路径
  6. DispatcherServlet是如何找到浏览器所请求的文件的?

    《前置控制器》

    • 所有的文件都放在了src/main/resources目录下的static目录中,编译后static目录就会被放在target/classes下,这个目录是类加载路径
    • 首先通过HttpServletRequest获取请求中的抽象路径(uri)的值
    • 然后使用当前类DispatcherServlet.class.getClassLoader().getResource(“.”)定位类加载路径
    • 在类加载路径下定位static目录
    • 在根据抽象路径去static目录下定位请求的文件
  7. ClientHandler处理一次HTTP交互的步骤有哪些?

    • 解析请求,通过实例化HttpServletRequest来完成
    • 处理请求,通过调用DispatcherServlet的service方法来完成
    • 发送响应,通过调用HttpServletResponse的response方法来完成
  8. 如何判断浏览器发送的请求为空请求以及空请求的解决办法是什么?

    • 空请求是在HttpServetRequest解析请求行时读取到了空字符来判断是否为空请求
    • 解决办法:
      • 自定义异常EmptyRequestException,空请求异常
      • 在HttpServletRequest解析请求行方法parseRequestLine读取请求行时如果为空字符串则对外抛出空请求异常
      • 在HttpServletRequest的构造方法上继续声明对外抛出空请求异常
      • 在ClientHandler的异常处理机制中添加一个单独捕获空请求异常的catch,catch中不需要任何处理,目的仅为忽略处理请求和发送响应工作
  9. 如何让HttpServletResponse支持响应所有MIME类型?

    • 在src/main/resources下新建一个目录:META-INF
    • 将文件mime.types拷贝到META-INF中。(这个文件传奇老师会下发)
    • 在HttpServletResponse的setContentFile中使用实例化MimetypesFileTypeMap并调用其getContentType方法将正文文件传入来得到对应的MIME
    • 利用得到的MIME类型添加响应头Content-Type即可
  10. 请GET请求与POST请求传递表单数据的区别

    • GET请求提交表单数据时,表单数据会被拼接在URL的抽象路径部分的"?"右侧

    • POST请求则将表单数据体现在请求的消息正文中,并且在消息头中包含Content-Type和Content-Length说明

    • 当表单含有用户隐私信息或这含有附件上传时则要使用POST形式提交表单

  11. 浏览器提交中文数据时为何不能直接使用中文?又是如何传递中文的?

    • 以GET请求为例,由于数据会被包含在URL的抽象路径中,而抽象路径部分会被包含在请求的请求行中。HTTP协议要求请求的请求行和消息头部分使用的字符集只能是ISO8859-1,该字符集不支持中文,因此不能直接传递中文。
    • 通常我们会在页面上使用来指定页面字符集,浏览器会先将提交的中文按照该字符集转换为2进制,然后将2进制以16进行形式表示,并且每两位16进制(1字节内容)前加一个"%"的形式将中文内容拼接在抽象路径中传递过来
  12. 服务端如何解决传递中文问题?

    • 在解析请求时,在解析参数的过程中,使用类:URLDecoder的静态方法decode来将%XX这样的内容转换为对应的文字。
  13. 重定向是如何实现的?

    • 在HttpServletResponse类中定义一个方法:public void sendRedirect(String uri)
    • 该方法中首先将状态代码改为302,状态描述也改为对应的值
    • 在响应头中添加Location,并将重定向的路径最为该响应头的值
  14. 简述HandlerMapping类的作用以及初始化的过程。

    • 用于保存所有请求路径和处理该请求的某个Controller中业务方法的对应关系
    • 初始化过程是在static块中调用本类的对应初始化静态方法来完成初始化的。
      • 首先定位类加载路径下的com.webserevr.controller包
      • 获取该包中所有的class文件并根据文件名获取类名
      • 使用Class.forName加载对应的类并判断是否有注解@Controller标注,没有标注的类就略过。
      • 扫描该类所有所有的方法,并判断是否有被注解@RequestMapping标注,没有标注的方法就略过。
      • 获取该方法上的注解并通过注解对象获取参数,参数就是该方法处理的请求路径。
      • 然后将请求路径作为key,方法对象作为value保存在HandllerMapping的静态Map类型的属性中完成初始化。
  15. 如何实现一个类的单例模式

    1. 私有化构造方法
    2. 提供一个静态的私有的当前类性的属性,并初始化
    3. 提供一个公开的,静态的获取当前类实例的方法
  16. Controller上加注解与在DispatcherServlet中添加分支调用Controller中的方法的好处是?

    • 添加新的业务时,DispathcerServlet无需进行修改,解除了DispatcherServlet与Controller的耦合。

猜你喜欢

转载自blog.csdn.net/weixin_47852232/article/details/127846254